Skip to content

fix(update): escape systemd update handoffs#85414

Merged
giodl73-repo merged 1 commit into
openclaw:mainfrom
giodl73-repo:fix/84068-systemd-handoff
May 24, 2026
Merged

fix(update): escape systemd update handoffs#85414
giodl73-repo merged 1 commit into
openclaw:mainfrom
giodl73-repo:fix/84068-systemd-handoff

Conversation

@giodl73-repo

@giodl73-repo giodl73-repo commented May 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes Update button no-op on systemd-supervised installs: handoff helper killed by unit cgroup before it runs #84068 by launching systemd-managed update handoff helpers through systemd-run --user --scope --collect so the helper moves out of openclaw-gateway.service before the gateway unit restarts.
  • Keeps launchd, schtasks, and non-systemd handoffs on the existing detached Node launch path.
  • Adds a systemd-only 2s restart grace even when a caller asks for restartDelayMs: 0, plus focused coverage for the transient scope command and restart scheduling.

Verification

2026-05-23 update after rebasing onto origin/main (32f91503be), head 35c99588ab:

  • node scripts/run-vitest.mjs src/gateway/server-methods/update-managed-service-handoff.test.ts src/gateway/server-methods/update.test.ts --reporter=verbose (4 files, 50 tests passed)
  • ./node_modules/.bin/oxfmt --check --threads=1 CHANGELOG.md src/gateway/server-methods/update-managed-service-handoff.ts src/gateway/server-methods/update-managed-service-handoff.test.ts src/gateway/server-methods/update.ts src/gateway/server-methods/update.test.ts
  • ./node_modules/.bin/oxlint src/gateway/server-methods/update-managed-service-handoff.ts src/gateway/server-methods/update-managed-service-handoff.test.ts src/gateway/server-methods/update.ts src/gateway/server-methods/update.test.ts
  • git diff --check origin/main...HEAD

Earlier verification before the rebase:

  • pnpm install
  • OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs src/gateway/server-methods/update-managed-service-handoff.test.ts src/gateway/server-methods/update.test.ts src/commands/status-update-restart.test.ts -- --reporter=verbose
  • pnpm exec oxlint --tsconfig config/tsconfig/oxlint.core.json src/gateway/server-methods/update-managed-service-handoff.ts src/gateway/server-methods/update-managed-service-handoff.test.ts src/gateway/server-methods/update.test.ts src/gateway/server-methods/update.ts
  • node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo
  • git diff --check
  • codex review --uncommitted

Note: node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json ... was blocked in this worktree before linting changed files by an unrelated WhatsApp boundary artifact failure: missing baileys types in extensions/whatsapp. Direct focused oxlint on changed files passed.

Real behavior proof

Behavior addressed: systemd-supervised Control UI/package update handoffs no longer leave the update helper inside openclaw-gateway.service, where the helper can be killed by the gateway unit restart before it writes handoff.log or runs openclaw update.

Real environment tested: WSL Ubuntu-24.04 checkout at /root/src/openclaw-85414, Node/Vitest via repo wrapper. Earlier proof also used a WSL2 Ubuntu 24.04 user-systemd environment with a real systemctl --user unit, documented in the PR comments.

Exact steps or command run after this patch: node scripts/run-vitest.mjs src/gateway/server-methods/update-managed-service-handoff.test.ts src/gateway/server-methods/update.test.ts --reporter=verbose

Evidence after fix: The focused tests verify the production handoff path chooses systemd-run --user --scope --collect --unit=openclaw-update-<handoff>.scope <node> <handoff.cjs> <handoff.json> for supervisor: "systemd", while preserving service identity env and stripping transient systemd invocation hints. The update scheduling test verifies the minimum 2000ms systemd restart grace when restartDelayMs: 0 is requested.

Observed result after fix: The focused suite passed: 4 test files, 50 tests. The systemd handoff starter spawns systemd-run instead of a plain detached Node child, and update.run schedules the gateway restart with enough grace for the transient scope handoff to leave the service cgroup.

What was not tested: I did not repeat the live package-upgrade/systemd-unit E2E after this rebase; the changed behavior is covered by the production-path tests plus the earlier live WSL systemd proof in the PR discussion.

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

clawsweeper Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

Latest ClawSweeper review: 2026-05-24 01:31 UTC / May 23, 2026, 9:31 PM ET.

Workflow note: Future ClawSweeper reviews update this same comment in place.

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.

PR Surface
Source +112, Tests +98, Docs +1. Total +211 across 5 files.

View PR surface stats
Area Files Added Removed Net
Source 2 116 4 +112
Tests 2 101 3 +98
Docs 1 1 0 +1
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 5 218 7 +211

Summary
Routes systemd managed update handoffs through systemd-run --user --scope --collect, adds a 2s systemd restart grace, and extends focused update handoff tests plus the changelog.

Reproducibility: yes. The linked issue gives a concrete Linux user-systemd failure, and current main/release source still starts the helper as a plain detached child before restarting; I did not rerun the live current-main failure in this read-only review.

PR rating
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Summary: The PR is a focused bug fix with strong targeted systemd proof and tests, with only packaged end-to-end upgrade proof left as maintainer discretion.

Rank-up moves:

  • A maintainer can run one installed user-systemd package update smoke if they want full upgrade proof beyond the posted handoff-level proof.
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.

Real behavior proof
Sufficient (logs): The PR discussion contains after-fix WSL2 user-systemd logs showing the helper/update command running in a separate transient scope after the service restart.

Risk before merge

  • The posted real proof exercises the handoff under a real WSL2 user-systemd unit, but it does not repeat a full packaged Control UI/npm upgrade on the final PR head.
  • The systemd path now depends on systemd-run being executable; that is the right systemd escape mechanism, but it is still an availability-sensitive restart path change.

Maintainer options:

  1. Accept the focused systemd proof (recommended)
    Maintainers can accept the WSL2 user-systemd log proof plus focused tests as enough evidence for the cgroup escape, while noting the full package-upgrade smoke was not repeated.
  2. Run one packaged user-systemd update smoke
    Before merge, a maintainer can exercise Update Now or update.run from an installed user-systemd gateway and confirm version change, handoff.log, healthy restart, and final sentinel.

Next step before merge
No automated repair is indicated; the remaining action is maintainer review of the protected restart-path PR, its CI, and the availability proof threshold.

Security
Cleared: The diff adds expected process spawning through argv arrays, sanitizes the transient unit suffix, and does not add dependencies, lockfile changes, lifecycle hooks, or secret handling.

Review details

Best possible solution:

Land the transient user-scope handoff after maintainer review and normal CI, preserving the existing non-systemd paths and treating any helper-never-ran diagnostic as a separate follow-up if needed.

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

Yes. The linked issue gives a concrete Linux user-systemd failure, and current main/release source still starts the helper as a plain detached child before restarting; I did not rerun the live current-main failure in this read-only review.

Is this the best way to solve the issue?

Yes. Moving only the systemd supervisor path to systemd-run --user --scope --collect addresses the cgroup-kill root cause while leaving launchd, schtasks, and non-systemd behavior on the existing handoff path.

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR discussion contains after-fix WSL2 user-systemd logs showing the helper/update command running in a separate transient scope after the service restart.
  • add rating: 🐚 platinum hermit: Current PR rating is 🐚 platinum hermit because proof is 🦞 diamond lobster, patch quality is 🐚 platinum hermit, and The PR is a focused bug fix with strong targeted systemd proof and tests, with only packaged end-to-end upgrade proof left as maintainer discretion.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (logs): The PR discussion contains after-fix WSL2 user-systemd logs showing the helper/update command running in a separate transient scope after the service restart.
  • remove rating: 🧂 unranked krab: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.
  • remove status: 📣 needs proof: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P1: The linked bug breaks the documented in-product update workflow for systemd-supervised Linux installs.
  • merge-risk: 🚨 availability: The PR changes the gateway restart/update handoff mechanism, so a bad systemd escape or restart grace would leave Update Now unavailable on Linux systemd installs.
  • rating: 🐚 platinum hermit: Current PR rating is 🐚 platinum hermit because proof is 🦞 diamond lobster, patch quality is 🐚 platinum hermit, and The PR is a focused bug fix with strong targeted systemd proof and tests, with only packaged end-to-end upgrade proof left as maintainer discretion.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (logs): The PR discussion contains after-fix WSL2 user-systemd logs showing the helper/update command running in a separate transient scope after the service restart.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR discussion contains after-fix WSL2 user-systemd logs showing the helper/update command running in a separate transient scope after the service restart.

What I checked:

  • Current main still uses plain detached Node handoff: At current main, startManagedServiceUpdateHandoff writes the helper files and spawns params.execPath ?? process.execPath with [scriptPath, paramsPath], detached: true; there is no systemd scope escape in this path. (src/gateway/server-methods/update-managed-service-handoff.ts:371, d92501dbf34e)
  • Latest release has the same shipped behavior: The latest release tag v2026.5.22 still shows the plain detached Node spawn and the release/current-main grep for systemd-run, resolveHandoffSpawn, and SYSTEMD_HANDOFF_RESTART_GRACE_MS found no matches. (src/gateway/server-methods/update-managed-service-handoff.ts:371, a374c3a5bfd5)
  • PR adds the systemd transient scope path: The PR head resolves systemd-run, builds a sanitized openclaw-update-*.scope unit name, and returns argv for systemd-run --user --scope --collect --unit=... <node> <handoff.cjs> <handoff.json> when supervisor is systemd. (src/gateway/server-methods/update-managed-service-handoff.ts:383, 35c99588abed)
  • PR adds systemd restart grace and focused tests: The PR passes the detected supervisor into the handoff starter and clamps systemd handoff restarts to at least 2000ms; tests assert both the transient scope command and the 2000ms scheduling behavior. (src/gateway/server-methods/update.ts:49, 35c99588abed)
  • Dependency contract check: Local systemd-run --help lists --user, --scope, --unit=UNIT, --collect, and command arguments, matching the PR's argv-based invocation shape.
  • Real behavior proof was added after the first bot review: The PR discussion includes after-fix WSL2 Ubuntu user-systemd output showing the service restart and the update command running in app.slice/openclaw-update-wsl-proof.scope with handoff.log recording exit code 0. (35c99588abed)

Likely related people:

  • steipete: Visible blame and history show Peter Steinberger introduced the current managed handoff files and earlier gateway update restart flow, and recently touched the same gateway update surface. (role: feature owner / recent area contributor; confidence: high; commits: 4cc2b293db9e, 71c31266a1db, 4da6a7f21206; files: src/gateway/server-methods/update-managed-service-handoff.ts, src/gateway/server-methods/update.ts, src/infra/supervisor-markers.ts)
  • Rami Abdelrazzaq: History shows adjacent hardening of the gateway self-update restart path that this PR now changes. (role: adjacent update restart contributor; confidence: medium; commits: 0b8b95f2c97f; files: src/gateway/server-methods/update.ts)
  • dimatu: History shows a recent supervisor marker change in the shared detection helper used to choose the systemd handoff path. (role: adjacent supervisor detection contributor; confidence: low; commits: cf796e2a223f; files: src/infra/supervisor-markers.ts)

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

@clawsweeper clawsweeper Bot added 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. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels May 22, 2026
@clawsweeper

clawsweeper Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: ✨ glimmer Velvet Review Wisp

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

Rarity: ✨ glimmer.
Trait: collects tiny proofs.
Image traits: location review cove; accessory green check lantern; palette charcoal, cyan, and signal green; mood bright-eyed; pose peeking out from the egg shell; shell smooth pearl shell; lighting calm overcast light; background subtle branch markers.
Share on X: post this hatch
Copy: My PR egg hatched a ✨ glimmer Velvet Review Wisp in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@giodl73-repo

Copy link
Copy Markdown
Contributor Author

Real behavior proof: systemd handoff survives gateway service restart

Behavior addressed: Update handoff helper is launched outside the openclaw-gateway.service cgroup for systemd-supervised installs, so it survives the gateway unit restart and can run the update command.

Real environment tested: local WSL2 Ubuntu 24.04 user-systemd environment, Linux 6.6.87.2-microsoft-standard-WSL2, systemd 255.4-1ubuntu8.14, systemd-run --user --scope available and working.

Exact steps or command run after this patch: created a real systemctl --user unit named openclaw-gateway-proof.service with KillMode=control-group. The unit ran Node from this PR checkout and called startManagedServiceUpdateHandoff with supervisor=systemd, handoffId=wsl-proof, and restartDelayMs=0. After handoff-started.json was written, ran systemctl --user restart openclaw-gateway-proof.service while the handoff helper was waiting for the parent PID to exit.

Evidence after fix:

handoff-started:
{
  "status": "started",
  "pid": 1692621,
  "command": "openclaw update --yes --timeout 5",
  "logPath": "/tmp/openclaw-update-run-handoff-OgHMxU/handoff.log",
  "servicePid": 1692595
}

service-restarted:
restarted pid=1692631 at=2026-05-22T15:33:56.985Z

update-command-ran:
updatedAt=2026-05-22T15:33:57.335Z
args=update --yes --json --timeout 5
pid=1692640
ppid=1692621
cgroup=0::/user.slice/user-0.slice/[email protected]/app.slice/openclaw-update-wsl-proof.scope;

handoff-log:
[2026-05-22T15:33:57.218Z] starting managed update command: openclaw update --yes --timeout 5
[2026-05-22T15:33:57.222Z] managed update command pid=1692640
[2026-05-22T15:33:57.354Z] managed update command exited code=0 signal=null

Observed result after fix: the restarted gateway-proof service ran in app.slice/openclaw-gateway-proof.service, while the handoff/update command ran in separate transient scope app.slice/openclaw-update-wsl-proof.scope and completed with exit code 0 after the service restart.

What was not tested: a full packaged npm upgrade against a production openclaw-gateway.service. Remote Crabbox proof was attempted but blocked before command execution: AWS runs run_58a14cc15ac9 / lease cbx_7de29d1525db and run_72d49c7e458f / lease cbx_41ad1ed803d3 both timed out waiting for SSH; Hetzner had invalid token, Namespace CLI was missing, Daytona auth was missing, and Blacksmith Testbox did not return a tbx_ id.

@giodl73-repo
giodl73-repo force-pushed the fix/84068-systemd-handoff branch from dc67477 to 35c9958 Compare May 24, 2026 01:25
@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 May 24, 2026
@giodl73-repo
giodl73-repo merged commit 1f28c3e into openclaw:main May 24, 2026
123 of 129 checks passed
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
SYU8384 pushed a commit to SYU8384/openclaw that referenced this pull request Jun 3, 2026
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
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 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: M 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.

Update button no-op on systemd-supervised installs: handoff helper killed by unit cgroup before it runs

1 participant