Skip to content

feat(update): surface 'updates paused' for diverged devices + one-click reset to channel - #223

Merged
KrasimirKralev merged 1 commit into
ID-Robots:betafrom
KrasimirKralev:feature/update-honesty
Jun 24, 2026
Merged

KrasimirKralev merged 1 commit into
ID-Robots:betafrom
KrasimirKralev:feature/update-honesty

Conversation

@KrasimirKralev

Copy link
Copy Markdown
Contributor

Why

A device on a non-release branch with local commits gets every update silently withheld: getTargetVersion only offers a release tag that's a forward-ancestor of HEAD, so a diverged HEAD returns null → 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 on clawbox.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.ts
    • getChannelDivergence() — detects local commits the release channel lacks (ahead > 0 && behind > 0, via a single git rev-list --left-right --count origin/<channel>...HEAD). Requires behind > 0 so a box merely ahead of the channel (a dev box on a local tag, nothing newer to install) isn't nagged. Reuses the fetch getTargetVersion already ran — no extra network I/O.
    • getVersionInfo now returns diverged / pausedReason / channel.
    • forceResetToChannel() — pins .update-branch to the channel (the pin, else main; 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 over forceResetToChannel.
  • SystemUpdateApp.tsx — a paused state 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's versions.channel (single source of truth, can't drift from what the reset targets).
  • Unit tests for divergence detection (diverged vs behind-only/ahead-only).

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.
  • Reuses the existing, battle-tested update path (startUpdateupdateClawBoxAndReboot); the reset's reset --hard origin/<channel> is the same hard-sync used today.
  • Closes the silent-no-update gap for georgi, the telegram box, and any agent-modified customer box.

…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.
@KrasimirKralev
KrasimirKralev requested a review from a team as a code owner June 24, 2026 15:27
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@KrasimirKralev, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4abf683b-ec09-4f4e-83d3-9d255daf0071

📥 Commits

Reviewing files that changed from the base of the PR and between 65baf52 and 5080d55.

📒 Files selected for processing (4)
  • src/app/setup-api/update/reset/route.ts
  • src/components/SystemUpdateApp.tsx
  • src/lib/updater.ts
  • src/tests/unit/updater.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@KrasimirKralev
KrasimirKralev merged commit cd7fd53 into ID-Robots:beta Jun 24, 2026
7 checks passed
KrasimirKralev added a commit that referenced this pull request Jun 25, 2026
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant