Skip to content

fix(launchd): verify profile updater jobs by metadata#97264

Merged
steipete merged 4 commits into
openclaw:mainfrom
tayoun:fix/launchd-updater-metadata
Jul 9, 2026
Merged

fix(launchd): verify profile updater jobs by metadata#97264
steipete merged 4 commits into
openclaw:mainfrom
tayoun:fix/launchd-updater-metadata

Conversation

@tayoun

@tayoun tayoun commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

A macOS update handoff can leave behind a profile-scoped launchd label like ai.openclaw.<profile>.update.<timestamp>, which can keep rerunning openclaw update --yes after the gateway is already healthy.

PR #96924 was closed because a label-only matcher could also classify a legitimate gateway profile whose name contains .update.<timestamp>. This replacement keeps the bug fix but removes that false-positive path.

Why This Change Was Made

Profile-scoped update labels are now treated as candidates only. Before stale-job reporting or disabling, OpenClaw confirms the launchd job through metadata:

  • explicit OPENCLAW_UPDATE_RUN_HANDOFF=1 in the LaunchAgent environment, or
  • LaunchAgent ProgramArguments that look like an OpenClaw update command with update --yes, and not a gateway command.

Legacy ai.openclaw.update.* and ai.openclaw.manual-update.<digits> behavior remains unchanged. The scanner process environment marker is intentionally not trusted for other profile-scoped labels.

User Impact

OpenClaw can detect and disable the stuck profile-scoped updater loop, while status/doctor will not recommend disabling gateway jobs whose profile names happen to look update-shaped.

Evidence

  • pnpm exec oxfmt --check src/daemon/launchd.ts src/daemon/launchd.test.ts
  • node scripts/run-vitest.mjs src/daemon/launchd.test.ts -> 94 passed
  • node scripts/run-oxlint.mjs src/daemon/launchd.ts src/daemon/launchd.test.ts
  • pnpm tsgo:core
  • pnpm tsgo:core:test
  • git diff --check

macOS launchd behavior proof

Ran from this branch on macOS with two temporary LaunchAgents under gui/501, both created with RunAtLoad=false and removed immediately after capture. The positive control used profile-scoped updater metadata; the negative control used a gateway command under a label that still matches ai.openclaw.<profile>.update.<timestamp>.

macOS launchd profile-updater proof
domain=gui/501
temporary labels:
  updater=ai.openclaw.proofcody.update.20260627T160051Z
  gateway_control=ai.openclaw.dev.team.update.20260627T160051Z
launchctl list matching labels:
  -	0	ai.openclaw.dev.team.update.20260627T160051Z
  -	0	ai.openclaw.proofcody.update.20260627T160051Z
metadata excerpts:
  updater ProgramArguments=[/opt/homebrew/bin/openclaw, update, --yes, --json]
  updater EnvironmentVariables.OPENCLAW_UPDATE_RUN_HANDOFF=1
  gateway_control ProgramArguments=[/opt/homebrew/bin/openclaw, gateway, run]
OpenClaw findStaleOpenClawUpdateLaunchdJobs filtered output:
[
  {
    "label": "ai.openclaw.proofcody.update.20260627T160051Z",
    "lastExitStatus": 0
  }
]
expected: updater label reported; gateway_control label ignored
cleanup launchctl list remaining labels:
  none

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: M labels Jun 27, 2026
@clawsweeper

clawsweeper Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 9, 2026, 11:51 AM ET / 15:51 UTC.

Summary
The PR changes macOS launchd updater detection so profile-scoped update labels are treated as metadata-confirmed candidates before stale reporting or disabling.

PR surface: Source +131, Tests +338. Total +469 across 2 files.

Reproducibility: yes. Source inspection shows current main filters profile-scoped launchd updater labels before stale-job handling, and the PR body includes macOS terminal proof showing a metadata-confirmed updater reported while a gateway-shaped control is ignored.

Review metrics: 1 noteworthy metric.

  • Launchd action paths broadened: 2 paths changed. Both stale updater reporting and updater-job disabling now consider profile-scoped labels after metadata confirmation, which matters for availability review before merge.

Root-cause cluster
Relationship: canonical
Canonical: #97264
Summary: This PR is the current canonical implementation candidate replacing the closed unsafe label-only attempt for profile-scoped launchd updater cleanup.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] A maintainer should either accept the launchd availability risk or rerun the macOS LaunchAgent proof against the latest head before merge.

Risk before merge

  • [P1] The PR broadens profile-shaped launchd labels into stale-job reporting and disable paths after metadata confirmation; a bad metadata classification could flag or disable a valid macOS LaunchAgent.

Maintainer options:

  1. Land The Metadata-Gated Classifier (recommended)
    Merge if maintainers accept that LaunchAgent metadata and exact update command matching are enough to prevent disabling valid gateway jobs.
  2. Require Independent macOS Confirmation
    Have an owner rerun the temporary updater/gateway-control LaunchAgent proof against the latest head before merging.
  3. Pause For Broader Update Recovery
    Leave this PR open or close it only if maintainers decide profile-scoped cleanup should be handled with the wider macOS update recovery issue instead.

Next step before merge

  • [P2] No repair branch is needed because there are no blocking findings; the remaining action is maintainer review and availability-risk acceptance.

Maintainer decision needed

  • Question: Should maintainers accept the availability risk of enabling metadata-confirmed profile-scoped launchd updater labels in stale-job reporting and disable paths?
  • Rationale: The patch is narrowly implemented and proven, but it intentionally changes launchd job classification before user-visible diagnostics and disable actions.
  • Likely owner: steipete — They are the current assignee and have the strongest nearby history on the launchd updater diagnostics and disarm paths.
  • Options:
    • Land With Metadata Gate (recommended): Accept the demonstrated metadata and ProgramArguments gate as sufficient protection against gateway-label false positives.
    • Request Owner-Side macOS Proof: Ask for an independent maintainer macOS LaunchAgent run before merge if extra confidence is needed for launchd metadata behavior.
    • Pause For Narrower Scope: Hold the PR if maintainers want profile-scoped updater cleanup to wait for a broader macOS update recovery policy.

Security
Cleared: The diff reads existing LaunchAgent metadata and updates launchd classification tests; it adds no dependency, CI, package, credential, or supply-chain surface.

Review details

Best possible solution:

Land the metadata-gated shared launchd classifier after maintainer review, preserving gateway false-positive protection while fixing the profile-scoped updater loop.

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

Yes. Source inspection shows current main filters profile-scoped launchd updater labels before stale-job handling, and the PR body includes macOS terminal proof showing a metadata-confirmed updater reported while a gateway-shaped control is ignored.

Is this the best way to solve the issue?

Yes. The shared launchd scanner and disable helper are the right owner boundary because update cleanup, deep status, and doctor diagnostics consume the same stale-job classifier.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against ef53c20497e1.

Label changes

Label justifications:

  • P1: The PR addresses a macOS updater loop that can repeatedly restart or kill the managed Gateway during updates.
  • merge-risk: 🚨 availability: The diff changes launchd job classification before status/doctor reporting and disable actions, so a false positive could suppress or flag a valid launchd job.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-fix macOS terminal output for temporary LaunchAgents showing the profile updater reported and a gateway-shaped control ignored; private details should remain redacted in any follow-up proof.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix macOS terminal output for temporary LaunchAgents showing the profile updater reported and a gateway-shaped control ignored; private details should remain redacted in any follow-up proof.
Evidence reviewed

PR surface:

Source +131, Tests +338. Total +469 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 150 19 +131
Tests 1 338 0 +338
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 488 19 +469

What I checked:

  • Root repository policy read: Root AGENTS.md was read fully and its PR review, launchd/Gateway availability, proof, and merge-risk guidance applies to this review. (AGENTS.md:1, ef53c20497e1)
  • No scoped daemon policy found: No scoped AGENTS.md exists under src/daemon, so the root policy owns this launchd review surface.
  • Current main matcher is too narrow: Current main only accepts legacy ai.openclaw.update.* and numeric ai.openclaw.manual-update.* labels, so profile-scoped updater labels are not candidates on main. (src/daemon/launchd.ts:54, ef53c20497e1)
  • PR head adds metadata-gated profile candidates: The PR head adds profile-scoped label candidates and confirms them through LaunchAgent environment metadata or OpenClaw update --yes ProgramArguments before reporting stale jobs. (src/daemon/launchd.ts:56, 694c3885b5d7)
  • PR head applies the same gate before disable actions: Profile-scoped labels require metadata confirmation before the PR calls launchctl disable, with current-process handoff markers trusted only for launchd-backed current service identity. (src/daemon/launchd.ts:488, 694c3885b5d7)
  • Regression coverage includes positive and negative metadata cases: The PR tests profile updater ProgramArguments, explicit handoff marker metadata, generated env-file metadata, gateway-shaped false positives, and self-disarm behavior. (src/daemon/launchd.test.ts:567, 694c3885b5d7)

Likely related people:

  • steipete: Introduced the stale updater launchd status/doctor surface and legacy update launchd self-disarm path, and is currently assigned to this PR. (role: feature history contributor and current assignee; confidence: high; commits: 7acbb2260c4a, d5b87672f8ad, 0cb3bf1ee1b8; files: src/daemon/launchd.ts, src/daemon/launchd.test.ts, src/cli/update-cli/update-command.ts)
  • TurboTheTurtle: Authored the merged manual-update launchd recognition work on the same normalizer, stale scanner, status, doctor, and regression-test surface. (role: recent adjacent contributor; confidence: high; commits: 49e5091f180e; files: src/daemon/launchd.ts, src/daemon/launchd.test.ts, src/cli/daemon-cli/status.gather.ts)
  • vincentkoc: Closed the unsafe label-only predecessor with the metadata/ProgramArguments requirement and has recent adjacent update-handoff history. (role: predecessor reviewer and adjacent update contributor; confidence: medium; commits: 514b3365b54c; files: src/infra/update-managed-service-handoff.ts, src/daemon/launchd.ts, src/cli/update-cli/update-command.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-06-27T16:04:56.024Z sha 5f24cda :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jun 27, 2026
@tayoun

tayoun commented Jun 27, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 27, 2026
@steipete steipete self-assigned this Jul 9, 2026
@steipete
steipete merged commit 4f9a371 into openclaw:main Jul 9, 2026
97 checks passed
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

Simon-XYDT pushed a commit to Simon-XYDT/openclaw that referenced this pull request Jul 9, 2026
* fix(launchd): verify profile updater jobs by metadata

* fix(launchd): bind updater proof to job metadata

---------

Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
* fix(launchd): verify profile updater jobs by metadata

* fix(launchd): bind updater proof to job metadata

---------

Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: L status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants