feat(update): surface 'updates paused' for diverged devices + one-click reset to channel - #223
Conversation
…ck reset A device parked on a non-release branch with local commits (a dev box, or a customer box whose on-box agent committed to the repo) gets every update silently withheld — getTargetVersion only offers a tag that's a forward-ancestor of HEAD, so a diverged box looks identical to an up-to-date one. It just shows 'You're up to date' forever and never gets fixes. - updater.ts: getChannelDivergence() detects local commits the channel lacks (ahead>0 && behind>0, via one 'rev-list --left-right --count'); getVersionInfo surfaces diverged/pausedReason/channel. forceResetToChannel() pins .update-branch to the channel (so the hard-sync targets it, not the diverged branch) and runs the normal update. - New POST /setup-api/update/reset. - SystemUpdateApp: a 'paused' state replaces the misleading 'up to date' with the reason + a 'Reset to <channel> & update' button behind a confirm modal. - Unit tests for the divergence detection. The reset reuses the existing update flow (its reset --hard origin/<channel> already discards divergence); destructive, so it's gated by a confirmation.
|
Warning Review limit reached
More reviews will be available in 5 minutes and 52 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (4)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…227) Nine follow-ups from CodeRabbit's review of the v3.1.5 payload (already on beta): - gateway-pre-start.sh: gate the openai->codex migration on a USABLE codex JWT read from auth-profiles.json (openclaw.json holds only metadata), so an unauthenticated codex profile can't strand the device by dropping openai; accept legacy openai-codex:default. (#224) - gateway-pre-start.sh: require the full OAuth set (access+refresh+JWT id) before writing/preserving codex auth.json — partial files fail after token expiry. (#222) - issue-triage.mjs: ensure the category label exists before applying (gh issue edit fails atomically on any missing label). (#221) - issue-triage.yml: persist-credentials:false on checkout; pin @anthropic-ai/sdk. (#221) - reset/route.ts: return 409 when the reset doesn't start. (#223) - SystemUpdateApp.tsx: move autoFocus off the destructive reset button to Cancel. (#223) - updater.ts: only persist the channel pin after startUpdate() accepts. (#223) - updater.test.ts: add the ahead-only divergence case. (#223) Validated on a real Jetson via synthetic harnesses (migration gate: JWT->migrate, non-JWT/missing->skip, legacy key; full-OAuth-set health). /simplify-reviewed.
Why
A device on a non-release branch with local commits gets every update silently withheld:
getTargetVersiononly offers a release tag that's a forward-ancestor of HEAD, so a diverged HEAD returnsnull→ the System Update screen shows "You're up to date" forever and the device never receives fixes. We hit this three times — two dev boxes (georgi, the telegram-pairing box onclawbox.local) and the same trap can catch a customer box whose on-box AI agent commits to the repo. The box looks current and silently stops updating.What
updater.tsgetChannelDivergence()— detects local commits the release channel lacks (ahead > 0 && behind > 0, via a singlegit rev-list --left-right --count origin/<channel>...HEAD). Requiresbehind > 0so a box merely ahead of the channel (a dev box on a local tag, nothing newer to install) isn't nagged. Reuses thefetchgetTargetVersionalready ran — no extra network I/O.getVersionInfonow returnsdiverged/pausedReason/channel.forceResetToChannel()— pins.update-branchto the channel (the pin, elsemain; deliberately not the current branch) so the existing hard-sync targets the channel and discards the diverged commits, then runs the normal update. The pin also stops the device re-diverging silently.POST /setup-api/update/reset— thin route overforceResetToChannel.SystemUpdateApp.tsx— apausedstate replaces the misleading "up to date" hero with the reason + a "Reset to<channel>& update" button, gated behind a confirm modal (it's destructive — discards local commits). The "CURRENT" card is hidden while paused. The channel shown is the backend'sversions.channel(single source of truth, can't drift from what the reset targets).Notes / verification
bash/type-level: this is plain TS; the new logic is covered by the unit tests added here — CI runs typecheck + vitest. I'll watch CI + CodeRabbit and fix anything red before merge.startUpdate→updateClawBoxAndReboot); the reset'sreset --hard origin/<channel>is the same hard-sync used today.