OpenClaw
OpenClaw fences Cloud Worker workspaces after ambiguous SSH loss
A Cloud Worker rollback could race an apply whose SSH result vanished, leaving live and backup trees under two writers. The paired repair adds workspace-scoped ownership, durable phases and settlement before rollback; a separate worktree patch records why cleanup retained a checkout.
openclaw/openclaw issue #120655 is the inspected primary source: “Cloud Worker accepted rollback can race an indeterminate apply.” The related records below were inspected as supporting context rather than independent confirmation.
The facts
- openclaw/openclaw issue #120655 was created 2026-08-08T17:49:21Z and was closed at inspection; its title is “Cloud Worker accepted rollback can race an indeterminate apply.” - openclaw/openclaw PR #120717 was created 2026-08-08T21:32:47Z and was closed at inspection; its title is “fix(cloud-workers): preserve accepted workspace after SSH loss.” - openclaw/openclaw PR #120434 was created 2026-08-08T02:35:55Z and was open at inspection; its title is “feat(agents): record run-end worktree cleanup outcome; prove Workboard dirty retention.” - The repository reported 385580 stars, 5631 open issues, default branch main, and last push 2026-08-09T00:56:46Z. - The latest tagged-release baseline checked was v2026.7.1-2 published 2026-08-04T00:41:26Z.
What changed
openclaw/openclaw issue #120655 reports: Bug type Behavior bug (incorrect output/state without crash) Beta release blocker No Summary Cloud Worker accepted-workspace rollback can run concurrently with an apply whose SSH result was lost, allowing both commands to rename the same remote live and backup trees. Steps to reproduce 1. Complete a Cloud Worker turn whose accepted result must publish one or more paths back to the remote workspace. 2. Let the remote accepted-workspace apply command start, then drop the SSH transport before its exit status reaches the Gateway while leaving the remote Node process running. 3. Observe that workspace-accepted-sync.ts treats the non-successful SSH result as an apply failure and immediately starts rollback with the same transaction nonce. 4. Because the remote transaction script has no workspace-scoped operation lock or phase CAS, apply and rollback can both rename entries between the live and backup trees. The fault sequence is directly visible in src/gateway/worker-environments/workspace-accepted-sync.ts: apply is awaited, then every post-begin error enters the catch path and launches rollback. The corresponding remote operations in src/gateway/worker-environments/workspace-manifest-remote-script.ts mutate the same transaction, backup, and live paths
openclaw/openclaw PR #120717 reports: Closes #120655 What Problem This Solves Fixes an issue where a completed Cloud Worker turn could leave its accepted workspace result indeterminate when SSH disconnected during remote apply. The Gateway immediately started rollback even though the original remote apply could still be running, so both processes could rename the same live and backup trees concurrently. Why This Change Was Made Accepted-workspace publication now has one remote, workspace-scoped ownership boundary. Every begin, apply, settle, commit, rollback, and recovery action is serialized by an operation-and-nonce lock with exact owner identity and dead-owner reclamation. Durable phases record begun → applying → applied → committed; after an indeterminate SSH result, the Gateway settles the same nonce before deciding whether the operation completed. Observation failure is no longer rollback authority. If settlement times out, fails, or returns malformed state, the remote transaction remains pending and the local reconciliation layer keeps its SQLite rollback journal plus applied bytes pending. The next reconciliation restores the local journal first and then recovers the remote transaction. Definitive outcomes (begun, rolled-back, or an observed commit-retry
openclaw/openclaw PR #120434 reports: What Problem This Solves Follow-up recorded in #120362: the Workboard dirty-retention QA case had to be dropped because run-end worktree cleanup left no observable fact. agent.wait can resolve before the async subagent_ended cleanup hook, and nothing recorded whether cleanup ran or why it kept a checkout — so a retention assertion would have been false proof, and an operator looking at a surviving worktree had no way to know it was retained deliberately. Why This Change Was Made Per the Product Doctrine ("record facts where they happen; every action ends in a visible outcome or a recorded non-outcome"), removeIfLossless — the single lifecycle owner where the lossless/retain decision is made — now persists a durable outcome on the worktree registry row at every exit: removed-lossless, retained-busy (live run lease or competing remover), retained-dirty, retained-unpushed, retained-provisioned-drift, or failed with a bounded reason. Storage is a single additive run_end_cleanup_json column (declared in the canonical schema plus the idempotent lazy ensure; no schema-version bump — older readers tolerate it). The fact flows through the existing worktrees.list RPC and
Why it matters
Transport failure is not proof that remote mutation stopped. Recovery needs one durable owner and an observed phase, or the compensating action can corrupt the state it was meant to save. The operator test is whether visible output, retained state and authority still describe the same event after retries, background work or restart.
Current
The primary record was closed when captured on 2026-08-09. The tagged-release baseline was v2026.7.1-2 published 2026-08-04T00:41:26Z. Repository metadata, full source bodies, current pull requests and issues, releases, Google News, Hacker News, Lobsters, Metamesh and the rendered ClawCharts row were inspected. ClawCharts selected the subject; it did not prove the claim.
Evidence
The primary URL is https://github.com/openclaw/openclaw/issues/120655. Supporting records are https://github.com/openclaw/openclaw/pull/120717 and https://github.com/openclaw/openclaw/pull/120434. Source bodies, timestamps and states are preserved in the daily evidence bundle. Test counts and reproductions remain attributed to their authors unless identified as independently rerun.
Source boundary
Open work is described as open, closed work as closed, and operator reports as reports. A pull request is evidence of proposed or reviewed direction, not proof of a shipped release. Search residue, package mirrors and historically published source spines were excluded.
Operator take
Treat every lost acknowledgement after a remote write as indeterminate. Fence by operation identity, persist phases, and make retained workspaces explain themselves. Preserve a before-state receipt, make the smallest reversible change, and verify the original failure independently.
Caveat
Public project records are mutable. Status, scope and evidence can change after publication. This brief records the inspected state and does not authorize changes to a reader’s deployment.
Source inspected; source state, environment and release boundary remain explicit.