Skip to content

feat(updates): add one-click upgrade experience - #840

Draft
mcharles-square wants to merge 1 commit into
codex/one-click-updates-05-installer-bootstrapfrom
codex/one-click-updates-06-client-experience
Draft

feat(updates): add one-click upgrade experience#840
mcharles-square wants to merge 1 commit into
codex/one-click-updates-05-installer-bootstrapfrom
codex/one-click-updates-06-client-experience

Conversation

@mcharles-square

@mcharles-square mcharles-square commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Reviewable diff: +443/-24 across 6 files (excludes generated, test, and story files).

Summary

Completes the operator experience with explicit confirmation, RC warnings, durable progress, expected-restart recovery, terminal failure guidance, and success reload. The action is rendered only when Fleet reports a reachable host updater; every unsupported or partially configured host keeps the existing copy-command workflow.

Stack: #841#842#843#844#845#835#836#837#838#839#840. This is 6/6 of the one-click phase, relative to #839. It exposes the action only after #835#839 supply the safe executor path and preserves #844#845’s manual command whenever runtime capability is unavailable.

How it works

The existing update toast opens the update modal. When one_click_available is false, the modal retains the manual installer command. When true, the operator confirms the exact eligible version, with an additional no-downgrade warning for RCs, and the hook triggers the upgrade then polls durable status. Temporary Fleet disconnects during activation are treated as expected; polling resumes until success reloads the app or failure shows the host log and recovery command.

stateDiagram-v2
  [*] --> ManualFallback: "executor unavailable"
  [*] --> Confirmation: "executor reachable"
  Confirmation --> Progress: "confirm exact target"
  Progress --> Reconnecting: "Fleet restarts"
  Reconnecting --> Progress: "Fleet reachable"
  Progress --> Success: "operation succeeded"
  Progress --> Failure: "operation failed"
  Success --> Reload
  Failure --> RecoveryDetails
Loading

Areas of the code involved

Area / package / file What changed Why it matters for review
features/updates/api/useUpgradeOperation.ts Trigger, durable polling, disconnect handling, and terminal state Core client lifecycle and retry semantics
UpdateNotificationModal.tsx Confirmation, RC warning, progress, recovery, success, and manual fallback states Primary operator-facing safety review surface
useUpdateNotification.ts Connects the existing persistent toast to live upgrade state Ensures progress survives modal close/reopen and toast refreshes
AppLayout.tsx, useUpdateStatus.ts Mounts upgrade orchestration and observes capability changes Keeps the feature global and capability-gated
Focused client tests Covers unavailable executor, trigger errors, progress, disconnect, failure, and success Tests — review alongside state transitions
docs/plans/archive/...one-click-upgrade...md Records completed architecture and recovery contract Institutional context for future maintenance

Key technical decisions & trade-offs

  • Runtime capability gates the action, chosen over a static feature flag that could expose broken controls on unsupported hosts.
  • A disconnect during activation is a recoverable state, chosen over reporting failure while fleetd intentionally restarts.
  • RC confirmation explicitly states that downgrades are unavailable, matching the forward-only migration policy.
  • The manual command remains in the same modal, so executor loss never removes the established recovery path.

Testing & validation

  • 12 focused Vitest cases passed across upgrade orchestration, modal states, and update notifications.
  • npm run build:protoFleet passed TypeScript compilation and the production Vite build.
  • Repository client formatting, typecheck, and pre-push hooks passed.
  • End-to-end activation against a real systemd host is intentionally not covered by browser unit tests.

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Note: This is an automated security-focused code review generated by Codex.
It should be used as a supplementary check alongside human review.
False positives are possible - use your judgment.

Scope summary

  • Reviewed pull request diff only (19b00d7c572e3e6825233681cf89dd2ceffca6ae...f075b8ec0b9e66fb405059201ef83e9f6425d92c, exact PR three-dot diff)
  • Model: gpt-5.5

💡 Click "edited" above to see previous reviews for this PR.


Review Summary

Overall Risk: MEDIUM

Findings

[MEDIUM] Active upgrade state is never cleared when the updater returns no operation

  • Category: Reliability
  • Location: client/src/protoFleet/features/updates/api/useUpgradeOperation.ts:48
  • Description: The polling loop only updates local state when response.operation is present. If the host updater is reachable but returns no operation after the UI has already stored an active operation, the stale active operation remains in state indefinitely.
  • Impact: Operators can be left with a non-dismissible “upgrade in progress” modal and 2-second active polling even though the durable updater state has been cleared, lost, or reset. During an upgrade/recovery workflow this can hide the real terminal state and force a page reload or manual intervention.
  • Recommendation: Handle the empty-operation response explicitly. If an operation was active, either clear it and allow dismissal with a clear “status unavailable/lost” message, or convert it to a terminal failed/unknown state that includes recovery guidance. Also add a regression test for an active operation followed by { executorAvailable: true } with no operation.

[MEDIUM] Current upgrade progress can be hidden when a different release is offered

  • Category: Reliability
  • Location: client/src/protoFleet/features/updates/useUpdateNotification.ts:52
  • Description: release prefers the latest offered release over the recovered release for the active operation, and operationForRelease then drops the operation unless its target version matches that selected release. If an operation for v1.3.0 is still active or failed while release discovery starts offering v1.4.0, the UI suppresses the durable operation state.
  • Impact: The operator can lose visibility into an in-progress or failed upgrade, including host log and recovery command details. Because closeModal still treats the hidden operation as active, the modal can also become confusing or hard to dismiss while showing the wrong release prompt.
  • Recommendation: Give active and failed operations their own display path independent of the latest eligible offer. Prefer the operation’s target release while an operation exists, or keep separate state for “current operation” and “new available update” so a newer offer cannot mask recovery/progress for the operation already running.

Notes

The scoped diff is frontend-focused plus an archived plan document. I did not find changed backend auth, SQL, command execution, plugin, mining pool, or protobuf wire-format issues in this PR diff.


Generated by Codex Security Review |
Triggered by: @mcharles-square |
Review workflow run

@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from f8c41ce to 9178649 Compare July 30, 2026 08:50
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 9178649 to 4afd98a Compare July 30, 2026 09:03
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch 2 times, most recently from 2ce2ce5 to 5854595 Compare July 30, 2026 14:16
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 5854595 to 586f9e7 Compare July 30, 2026 15:25
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch 2 times, most recently from 6fc4d02 to 484cace Compare July 30, 2026 17:37
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 5e9330d to 00367ba Compare July 30, 2026 17:58
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 00367ba to d135c7b Compare July 31, 2026 04:55
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from d135c7b to 5193449 Compare July 31, 2026 05:04
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 5193449 to 374e43a Compare July 31, 2026 07:04
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch 2 times, most recently from 4b7d4d7 to c886d64 Compare July 31, 2026 07:52
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from c886d64 to 241756d Compare July 31, 2026 08:47
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch 2 times, most recently from 518a477 to 9513ab7 Compare July 31, 2026 14:12
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 9513ab7 to 930bc8b Compare July 31, 2026 14:50
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 930bc8b to 92ca0f1 Compare July 31, 2026 15:44
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 92ca0f1 to afd1c11 Compare July 31, 2026 16:08
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch 2 times, most recently from 513b515 to 217b698 Compare July 31, 2026 18:27
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 217b698 to f075b8e Compare July 31, 2026 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client documentation Improvements or additions to documentation javascript Pull requests that update javascript code review-policy: needs-review Managed by the Review Policy workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant