Skip to content

fix(ui): treat started managed-service handoff as pending update instead of skipped#87968

Closed
xydigit-sj wants to merge 1 commit into
openclaw:mainfrom
xydigit-sj:fix/dashboard-handoff-skipped-state
Closed

fix(ui): treat started managed-service handoff as pending update instead of skipped#87968
xydigit-sj wants to merge 1 commit into
openclaw:mainfrom
xydigit-sj:fix/dashboard-handoff-skipped-state

Conversation

@xydigit-sj

@xydigit-sj xydigit-sj commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #87889.

When a user clicks "Update now" in the Dashboard on a global install with a managed-service supervisor, the Gateway starts a managed-service handoff and returns ok=true with result.status="skipped" and reason="managed-service-handoff-started". The Dashboard code previously checked status === "ok" to decide success, so the handoff response fell through to the skipped-update banner even though the handoff was successfully started.

ClawSweeper review identified two additional issues in the initial PR; both are addressed in the latest push:

  • P2: The regression test used a fictional result.after.version that does not match the real gateway managed-service handoff payload. The real response contains status: "skipped", reason: "managed-service-handoff-started", and optionally before: { version }, but no after field.
  • P1: Because after.version was absent, pendingUpdateExpectedVersion became null, causing verifyPendingUpdateVersion to exit immediately and skip post-restart version verification.

Change

  • ui/src/ui/controllers/config.tsrunUpdate now treats any ok=true response as success/pending, regardless of result.status. This aligns the Dashboard with the Gateway contract: ok=true means either the update succeeded or the managed-service handoff was started.
  • runUpdate now derives pendingUpdateExpectedVersion through a three-tier fallback: result.after.version -> updateAvailable.latestVersion -> null. This ensures post-restart version verification stays active even when the gateway handoff response does not include an after version.
  • Added managed-service-handoff-started to the actionable guidance map so the banner text is informative if the handoff ever surfaces as an error.
  • Added optional updateAvailable to ConfigState so runUpdate can access the latest known version when needed.

Before:

  • Gateway returns ok=true, result.status=skipped, reason=managed-service-handoff-started, handoff.status=started
  • Dashboard sees status=skipped -> shows "Update skipped" error banner
  • User thinks update failed

After:

  • Dashboard sees ok=true -> sets pendingUpdateExpectedVersion (from after.version or updateAvailable.latestVersion) and returns without banner
  • Gateway restarts, UI polls update status, post-restart verification handles the rest

Files changed

  • ui/src/ui/controllers/config.ts — derive pending version via after.version ?? updateAvailable.latestVersion ?? null; add handoff guidance; add optional updateAvailable to ConfigState
  • ui/src/ui/controllers/config.test.ts — 2 tests: regression test with real handoff payload shape (no after, uses updateAvailable fallback), plus boundary test for null-fallback when neither after nor updateAvailable is present

Verification

node scripts/run-vitest.mjs ui/src/ui/controllers/config.test.ts

Test Files  1 passed (1)
Tests       41 passed (41)
Duration    2.45s

Real behavior proof

Behavior addressed: Dashboard shows "Update skipped" banner when a managed-service handoff is actually started (#87889).

Real environment tested: Local OpenClaw source checkout on branch fix/dashboard-handoff-skipped-state, Linux, Node 22.

Exact steps or command run after this patch:

Run the actual runUpdate source entrypoint with the real managed-service handoff payload (note the handoff.status: "started" that the gateway returns):

node --import tsx -e '
import { runUpdate } from "./ui/src/ui/controllers/config.ts";
import type { ConfigState } from "./ui/src/ui/controllers/config.ts";

const state = {
  client: {
    request: async () => ({
      ok: true,
      result: {
        status: "skipped",
        reason: "managed-service-handoff-started",
        before: { version: "2026.5.0" },
      },
      handoff: { status: "started", command: "openclaw update --yes --timeout 1800" },
    }),
  },
  connected: true,
  applySessionKey: "test",
  updateRunning: false,
  lastError: null,
  chatError: null,
  updateStatusBanner: null,
  pendingUpdateExpectedVersion: null,
  pendingUpdateHandoff: false,
  updateAvailable: { latestVersion: "2026.6.1" },
} as unknown as ConfigState;

await runUpdate(state);
console.log("pendingUpdateExpectedVersion:", state.pendingUpdateExpectedVersion);
console.log("pendingUpdateHandoff:", state.pendingUpdateHandoff);
console.log("updateStatusBanner:", state.updateStatusBanner);
console.log("updateRunning:", state.updateRunning);
console.log("lastError:", state.lastError);
'

Evidence after fix: Terminal capture from running the patched runUpdate source entrypoint with the real managed-service handoff payload:

pendingUpdateExpectedVersion: 2026.6.1
pendingUpdateHandoff: true
updateStatusBanner: null
updateRunning: false
lastError: null

Observed result after fix: When the gateway returns ok=true with status=skipped, reason=managed-service-handoff-started, and handoff.status=started, the Dashboard no longer shows an error banner. It sets pendingUpdateExpectedVersion to updateAvailable.latestVersion (2026.6.1) and marks pendingUpdateHandoff as true, so the post-restart version verification path can take over.

What was not tested: Live browser Dashboard click-through with a managed-service supervisor (the proof exercises the actual runUpdate source entrypoint).

Refs: #87889

@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui size: XS triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels May 29, 2026
@clawsweeper

clawsweeper Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 9, 2026, 8:45 AM ET / 12:45 UTC.

Summary
The branch updates application overlay update handling and tests so started managed-service handoffs use updateAvailable.latestVersion as the pending target version and do not show the skipped-update banner.

PR surface: Source +5, Tests +32. Total +37 across 2 files.

Reproducibility: yes. at source level: current main's gateway started-handoff response omits after.version, while the current UI overlay stores the pending expected version only from result.after.version. The PR proof also exercises the Dashboard click path in Docker/Chromium and shows the corrected pending UI state.

Review metrics: 1 noteworthy metric.

  • Closing reference: 1 open issue. The PR body uses closing syntax for the canonical Dashboard update report, so merge would resolve that issue automatically.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #87889
Summary: This PR is the active UI-side candidate fix for the canonical Dashboard managed-service handoff issue; the closed backend cwd PR is overlapping context, and the merged coalesced restart PR is an adjacent sibling update-flow change.

Members:

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

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
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] Decide whether the current proof is enough for the closing reference, or convert it to a non-closing reference before merge.

Risk before merge

  • [P1] Merging as-is will close Update from Dashboard skipped, works from CLI #87889, while the supplied proof shows the UI handoff state after clicking Update now but not the detached helper completing and the Dashboard observing the final upgraded version.
  • [P1] The branch is currently behind the base; GitHub reports it as mergeable, but final maintainer review should preserve the recently merged coalesced-update E2E sibling behavior.

Maintainer options:

  1. Accept UI-scope proof and merge (recommended)
    Keep the closing reference if maintainers agree the current proof covers the issue's remaining user-visible skipped-banner behavior.
  2. Keep the issue open after landing
    Change the PR body from a closing reference to a non-closing reference before merge so final upgraded-version proof can be tracked separately.
  3. Wait for final flow proof
    Ask for browser or log proof of the detached update completing and the Dashboard showing the upgraded version before merge.

Next step before merge

  • [P2] No automated code repair is needed; maintainer review should settle the linked-issue closure and proof-scope choice before merge.

Maintainer decision needed

  • Question: Should this PR keep the closing reference for Update from Dashboard skipped, works from CLI #87889, or should it reference that issue without closing until final upgraded-version proof exists?
  • Rationale: The code fix is narrow and source-backed, but merge semantics would close the broader Dashboard update report before the final post-handoff upgraded-version observation is proven.
  • Likely owner: steipete — Recent adjacent UI update work and the linked-issue closure choice are closest to the current overlay/update review boundary.
  • Options:
    • Keep the closing reference (recommended): Merge as-is if maintainers accept the Docker/Chromium handoff-state proof plus source contract as sufficient for the remaining observable issue.
    • Convert to a non-closing reference: Update the PR body to avoid auto-closing the linked issue, then land the UI fix while tracking final full-flow proof separately.
    • Request final upgraded-version proof: Pause merge until browser/log proof shows the detached handoff completes and the Dashboard observes the upgraded version.

Security
Cleared: The diff is limited to UI overlay state handling and colocated tests; it does not change dependencies, workflows, permissions, secrets, publishing, or downloaded-code execution.

Review details

Best possible solution:

Land the UI fix after maintainers either accept the current handoff-state proof as enough to close the linked Dashboard update issue or change the PR body to keep that issue open for final upgraded-version proof.

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

Yes at source level: current main's gateway started-handoff response omits after.version, while the current UI overlay stores the pending expected version only from result.after.version. The PR proof also exercises the Dashboard click path in Docker/Chromium and shows the corrected pending UI state.

Is this the best way to solve the issue?

Yes for the UI state layer: using the already-delivered updateAvailable.latestVersion is the narrowest maintainable way to keep post-restart verification active without changing the gateway protocol. The remaining question is issue-closure proof scope, not a different code fix.

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P2: This is a normal-priority Dashboard update workflow bug with a CLI/manual-update workaround and limited blast radius.
  • merge-risk: 🚨 other: Merging as-is could close the linked Dashboard update issue before maintainers settle whether final upgraded-version proof is still required.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The latest PR comment includes copied live output from a Docker/Chromium Dashboard click against the branch showing a started handoff, expected-version fallback, pending handoff state, and no skipped/error banner.
  • proof: sufficient: Contributor real behavior proof is sufficient. The latest PR comment includes copied live output from a Docker/Chromium Dashboard click against the branch showing a started handoff, expected-version fallback, pending handoff state, and no skipped/error banner.
Evidence reviewed

PR surface:

Source +5, Tests +32. Total +37 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 6 1 +5
Tests 1 38 6 +32
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 44 7 +37

What I checked:

  • Repository policy read: Root and UI-scoped AGENTS.md were read; the review applied the required whole-path PR review and UI-scope checks. (AGENTS.md:1, 07a7d596ff6e)
  • Current main UI gap: Current main computes expectedVersion only from response.result.after.version; started managed-service handoff responses take the pending-handoff branch with that value still null. (ui/src/app/overlays.ts:550, 07a7d596ff6e)
  • Gateway handoff contract: The gateway started-handoff branch returns status: "skipped", reason: "managed-service-handoff-started", optional before, no after, and reports ok: true when a handoff starts. (src/gateway/server-methods/update.ts:278, 07a7d596ff6e)
  • Reconnect verifier consumer: verifyPendingUpdateVersion reads the stored pending expected version and handoff flag, then polls update.status across reconnects; a null expected version weakens final-version verification. (ui/src/app/overlays.ts:355, 07a7d596ff6e)
  • PR implementation: At the current PR head, expectedVersion falls back from response.result.after.version to snapshot.updateAvailable.latestVersion, and the started-handoff branch stores that value before marking the handoff pending. (ui/src/app/overlays.ts:513, 1c92f2ace374)
  • PR regression coverage: The PR adds overlay tests for the real no-after managed-service handoff payload and the null-fallback boundary when no updateAvailable value exists. (ui/src/app/overlays.test.ts:148, 1c92f2ace374)

Likely related people:

  • shakkernerd: Authored the merged supervised update handoff UI work and follow-up polling behavior that this PR extends. (role: recent area contributor; confidence: high; commits: 862790fbd7f4, 906158f5723f; files: ui/src/ui/controllers/config.ts, ui/src/ui/app-gateway.ts, ui/src/ui/app-gateway.node.test.ts)
  • steipete: Co-authored the merged coalesced update feedback change on the same overlay path and authored recent UI lifecycle boundary work touching the current file. (role: adjacent UI/update reviewer; confidence: medium; commits: ae6da5bc77a9, deb7faf7b066; files: ui/src/app/overlays.ts, ui/src/e2e/update-coalesced.e2e.test.ts)
  • goutamadwant: Authored the merged coalesced update restart PR on the same runUpdate success path that this PR now changes nearby. (role: adjacent contributor; confidence: medium; commits: ae6da5bc77a9; files: ui/src/app/overlays.ts, ui/src/e2e/update-coalesced.e2e.test.ts)
  • vincentkoc: Current-line blame in the latest release snapshot points to the old controller implementation that still lacked the fallback, useful for shipped-behavior provenance rather than root-cause ownership. (role: release-path carrier; confidence: low; commits: e085fa1a3ffd; files: ui/src/ui/controllers/config.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-25T01:48:00.463Z sha 97f7ea1 :: 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. P2 Normal backlog priority with limited blast radius. labels May 29, 2026
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request May 29, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
@xydigit-sj

Copy link
Copy Markdown
Contributor Author

ClawSweeper's P1/P2 concerns from the initial review have been addressed in the latest push:

  • P2 (payload shape): The regression test now uses the real gateway managed-service handoff payload — status: "skipped", reason: "managed-service-handoff-started", optional before: { version }, and no after field.
  • P1 (version verification gap): runUpdate now derives pendingUpdateExpectedVersion through a three-tier fallback (result.after.versionupdateAvailable.latestVersionnull), so post-restart version verification stays active even when the handoff response lacks an after version.

The remaining P1 blocker is real behavior proof from a live managed-service Dashboard update. I don't have access to a managed-service environment to capture screenshots or live runtime logs for this path. Would a maintainer be able to apply a proof override, or is there another way to satisfy this gate without a live managed-service setup?

Happy to make additional code changes if needed.

@xydigit-sj

Copy link
Copy Markdown
Contributor Author

Hi maintainers,

Following ClawSweeper's review, I acknowledge that this PR is missing real behavior proof from a live managed-service Dashboard update path.

The fix has been verified through colocated unit tests that mock the exact gateway response shape for the managed-service handoff (ok=true, status=skipped, reason=managed-service-handoff-started, no after field). The tests confirm:

  • pendingUpdateExpectedVersion is populated from updateAvailable.latestVersion when after.version is absent
  • The skipped-update banner is not shown for started handoffs
  • Graceful null fallback when neither version source is available

However, I don't have access to a managed-service OpenClaw install (e.g., systemd/package-manager supervised) in my local dev environment, which is needed to capture live Dashboard proof of the actual handoff flow.

Would a maintainer with access to a managed-service test environment be able to either:

  1. Validate this path and record a proof: override, or
  2. Point me to a way to simulate the managed-service handoff locally for proof purposes?

The code and tests are otherwise ready for review. Thanks!

@xydigit-sj
xydigit-sj force-pushed the fix/dashboard-handoff-skipped-state branch from 836f599 to 6d5b84e Compare June 5, 2026 08:38
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 5, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels Jun 6, 2026
@xydigit-sj
xydigit-sj force-pushed the fix/dashboard-handoff-skipped-state branch from 6d5b84e to 28c4ac5 Compare June 6, 2026 01:27
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 6, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
@clawsweeper clawsweeper Bot added 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 6, 2026
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 6, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
@xydigit-sj
xydigit-sj force-pushed the fix/dashboard-handoff-skipped-state branch 2 times, most recently from d76a802 to 7274584 Compare June 6, 2026 04:54
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 6, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jun 6, 2026
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 6, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
@xydigit-sj
xydigit-sj force-pushed the fix/dashboard-handoff-skipped-state branch 2 times, most recently from 968d2de to 67bc16e Compare June 6, 2026 06:30
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 6, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 11, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
@xydigit-sj
xydigit-sj force-pushed the fix/dashboard-handoff-skipped-state branch from eb6adce to c356225 Compare June 11, 2026 05:30
@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. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels Jun 11, 2026
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 11, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
@xydigit-sj
xydigit-sj force-pushed the fix/dashboard-handoff-skipped-state branch from c356225 to 4dc41f6 Compare June 11, 2026 08:31
@clawsweeper clawsweeper Bot added rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. and removed 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. labels Jun 11, 2026
@xydigit-sj

Copy link
Copy Markdown
Contributor Author

Quick update on the two remaining CI failures on this run:

  • checks-node-agentic-agents-core-models: src/agents/anthropic-transport-stream.test.tsmaps unsupported xhigh to high effort for Claude 4.6 transport runs fails with expected undefined to deeply equal { type: 'auto' }. This is in the agents core transport layer, unrelated to the UI controller changes in this PR.

  • checks-node-agentic-agents-core-runtime: src/agents/simple-completion-runtime.test.tscan preserve asynchronous provider model discovery fails with a mock assertion error. Also in agents core, unrelated to this PR.

The checks-node-core-ui shard (which covers the changed controller surface) passed successfully. Both failures appear to be pre-existing issues in src/agents/, not caused by the ui/src/ui/controllers/ changes here.

On the real behavior proof: I still don't have access to a managed-service environment to capture live Dashboard proof. The patch is otherwise rated platinum hermit by ClawSweeper. If a maintainer is able to validate this path or apply a proof: override, this should be ready for merge. Happy to make any additional code changes if needed.

xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 11, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
@xydigit-sj
xydigit-sj force-pushed the fix/dashboard-handoff-skipped-state branch from 4dc41f6 to 70fe257 Compare June 11, 2026 09:31
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 🛠️ actively grinding The PR author has acted after the latest ClawSweeper review and work remains. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. status: 🛠️ actively grinding The PR author has acted after the latest ClawSweeper review and work remains. labels Jun 11, 2026
@xydigit-sj
xydigit-sj force-pushed the fix/dashboard-handoff-skipped-state branch from 70fe257 to 7389efb Compare June 11, 2026 10:31
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 11, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
xydigit-sj added a commit to xydigit-sj/openclaw that referenced this pull request Jun 11, 2026
…ks after.version

ClawSweeper review (openclaw#87968) identified two issues:

1. P2: The regression test used a fictional result.after.version that does
   not match the real gateway managed-service handoff payload. The real
   response contains status: "skipped", reason: "managed-service-handoff-started",
   and optionally before: { version }, but no after field.

2. P1: Because after.version was absent, pendingUpdateExpectedVersion became
   null, causing verifyPendingUpdateVersion to exit immediately and skip
   post-restart version verification.

Fix:
- Add optional updateAvailable to ConfigState so runUpdate can access the
  latest known version when the gateway handoff response does not include
  an after version.
- Use a three-tier fallback: after.version -> updateAvailable.latestVersion -> null.
- Update the regression test to use the real handoff payload shape and assert
  that pendingUpdateExpectedVersion is derived from updateAvailable.
- Add a second test for the null-fallback path when neither after nor
  updateAvailable is present.

Refs: openclaw#87889
@xydigit-sj

Copy link
Copy Markdown
Contributor Author

Real behavior proof for the managed-service handoff UI fix.

Environment

  • Local Docker container: public-docker-virtual.artsz.zte.com.cn/library/node:24-bookworm
  • OpenClaw built from this branch (fix/dashboard-handoff-skipped-state) at /app
  • Git install surface confirmed via mounted ~/.gitconfig [safe] directory = /app
  • systemd context faked with INVOCATION_ID and OPENCLAW_SYSTEMD_UNIT
  • systemd-run replaced by a minimal pass-through shim so the handoff process can start inside the container
  • Dashboard device auth disabled via gateway.controlUi.dangerouslyDisableDeviceAuth

Steps

  1. Start gateway in the container.
  2. Open Dashboard in Chromium via Playwright.
  3. Inject updateAvailable = { currentVersion: "2026.6.2", latestVersion: "2026.6.8" }.
  4. Click the update banner "Update now" button.

update.run RPC response (raw)

{
  "ok": true,
  "result": {
    "status": "skipped",
    "mode": "git",
    "root": "/app",
    "reason": "managed-service-handoff-started",
    "before": { "version": "2026.6.2" },
    "steps": [
      {
        "name": "managed-service update handoff",
        "command": "openclaw update --yes",
        "cwd": "/app",
        "durationMs": 20,
        "exitCode": null
      }
    ],
    "durationMs": 20
  },
  "handoff": {
    "status": "started",
    "pid": 607,
    "command": "openclaw update --yes"
  },
  "restart": {
    "ok": true,
    "pid": 1,
    "signal": "SIGUSR1",
    "delayMs": 2000,
    "reason": "update.run",
    "mode": "emit",
    "coalesced": false,
    "cooldownMsApplied": 0,
    "emitHooksQueued": false
  }
}

UI state after clicking "Update now"

{
  "connected": true,
  "pendingUpdateHandoff": true,
  "pendingUpdateExpectedVersion": "2026.6.8",
  "updateStatusBanner": null,
  "updateRunning": false,
  "lastError": null
}

Verification

  • pendingUpdateHandoff becomes true, confirming the handoff is treated as a pending update.
  • pendingUpdateExpectedVersion is "2026.6.8", derived from updateAvailable.latestVersion because the gateway handoff payload has no after.version.
  • updateStatusBanner stays null, confirming no error/warn banner is shown.
  • This matches the intended fix in ui/src/ui/controllers/config.ts.

Notes

  • Screenshot (screenshot.png) and raw gateway logs (gateway.log) were captured during the run. I can upload them in a follow-up comment if useful; GitHub CLI does not support direct file attachments to PR comments.
  • Gateway logs show update.run completed ... status=skipped and the handoff command openclaw update --yes being started under the fake systemd supervisor.

@xydigit-sj

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Real behavior proof has been added to this PR (see comment on 2026-06-24). The proof demonstrates the managed-service Dashboard handoff state is now treated as pending update instead of skipped in a local Docker environment built from this branch. Please re-run review.

@clawsweeper

clawsweeper Bot commented Jun 25, 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.

@xydigit-sj

Copy link
Copy Markdown
Contributor Author

Closing as superseded by #112987.\n\nThe handoff-as-pending behavior this PR originally implemented has since landed in main via the refactor that moved update-overlay helpers into ui/src/app/update-overlay-helpers.ts. The remaining gap—falling back to updateAvailable.latestVersion when the gateway handoff response omits after.version—is now addressed by #112987 with a focused change and a regression test.

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

Labels

app: web-ui App: web-ui merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S 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 from Dashboard skipped, works from CLI

1 participant