Skip to content

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

Open
mcharles-square wants to merge 12 commits into
mainfrom
codex/one-click-updates-06-client-experience
Open

feat(updates): add one-click upgrade experience#840
mcharles-square wants to merge 12 commits into
mainfrom
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: +917/-8 across 5 files (excludes generated, test, and story files).

Summary

Adds the one-click upgrade workflow to Settings > Updates: exact-version confirmation, RC warnings, durable progress, expected restart recovery, failure guidance, and success reload. The normal application shell remains intentionally passive—it only advertises an available version and routes operators to Settings—while unsupported hosts retain the release-specific manual install command.

Stack: #841#842#843#844#845#835#836#837#838#839#840. This is 6/6 of the one-click phase and the diff is relative to #839. The merged ancestors provide release discovery, permission-gated APIs, durable host execution, and the passive update indicator; #839 installs that executor on supported hosts. Host mutation is intentionally out of scope here, and progress is intentionally not tracked across every Fleet view.

How it works

The passive version pill navigates an authorized operator to /settings/updates. The route loads the current eligible release, capability, and manual command, while separately checking durable updater status so an operation started in another tab or recovered after navigation takes precedence over a newer offer. A one-click action appears only when Fleet reports a reachable executor; confirmation sends only the exact eligible version, and fleetd revalidates it before host mutation.

During an operation the route uses completion-based polling, preserves the last phase through the expected Fleet restart, and recovers host state when the operator returns. Ambiguous trigger outcomes keep competing controls locked. If the executor remains unreachable after the bounded reconciliation window, the manual command stays locked until the operator explicitly confirms on-host that no upgrade is running; a reachable executor reporting no matching operation instead refreshes the eligible release before retry.

flowchart LR
  S["Passive version pill"] --> R["Settings > Updates"]
  R --> U["GetUpdateStatus: release, capability, manual command"]
  R --> O["GetUpgradeStatus: durable host operation"]
  U --> C{"Executor reachable?"}
  C -->|"yes"| X["Confirm exact target"]
  C -->|"no"| M["Copy manual install command"]
  X --> T["TriggerUpgrade(target version)"]
  T --> P["Route-owned progress and recovery"]
  O --> P
  P --> F["Failure details or explicit manual fallback"]
  P --> D["Success and reload"]
Loading
sequenceDiagram
  participant U as "Authorized operator"
  participant S as "Fleet shell"
  participant R as "Updates route"
  participant F as "fleetd"
  participant X as "Host updater"

  S->>F: "Discover eligible version"
  F-->>S: "Version-only indicator"
  U->>S: "Open update"
  S->>R: "Navigate to /settings/updates"
  R->>F: "GetUpdateStatus + GetUpgradeStatus"
  F-->>R: "Offer, capability, durable operation"
  U->>R: "Confirm exact target"
  R->>F: "TriggerUpgrade(target version)"
  F->>X: "Start validated operation"
  R-->>F: "Poll without overlap"
  opt "Operator leaves the route"
    U->>R: "Return later"
    R->>F: "Recover durable status"
  end
  F-->>R: "Active, failed, or succeeded"
  R-->>U: "Progress, recovery, or reload"
Loading

Areas of the code involved

Area / package / file What changed Why it matters for review
features/settings/components/Updates.tsx Owns capability-gated actions, control locking, status reconciliation, and route-level recovery Confirms the workflow stays local to Settings and preserves the manual path
features/settings/components/UpgradeOperationModal.tsx Adds confirmation, RC warning, progress, reconnect, failure, success, and explicit manual-unlock states Primary operator-facing safety surface
features/updates/api/useUpgradeOperation.ts Adds bounded RPCs, non-overlapping polling, session recovery, durable-operation precedence, and ambiguous-outcome handling Core lifecycle and concurrency review surface
copyInstallCommand.ts Updates the stale ownership comment after removing the global modal Confirms the helper now serves the Settings fallback
Focused client tests Covers route integration, lifecycle transitions, target preservation, auth loss, disconnects, and fallback confirmation Tests — review alongside each state owner
docs/plans/archive/...one-click-upgrade...md Records the completed route-owned architecture and current trust/recovery boundaries Institutional context for future maintenance

Key technical decisions & trade-offs

  • Settings owns confirmation and progress; the shell keeps only a passive link, avoiding lifecycle state across every route.
  • Durable host status is authoritative; browser session storage records only which terminal result belongs to this tab and survives route remounts.
  • Polls schedule only after the prior request completes, with bounded RPCs, avoiding overlapping requests during a restart.
  • An active host operation supersedes a newer release offer; the UI never exposes two competing targets.
  • Unknown trigger outcomes fail closed. Manual fallback requires explicit host confirmation after the bounded wait rather than silently unlocking a potentially overlapping install.
  • Failed operations retain the established manual command and expose the host log/recovery command; automatic rollback remains out of scope because migrations are forward-only.

Testing & validation

  • 79 focused Vitest cases passed across Settings integration, upgrade lifecycle, modal states, the passive indicator, and AppLayout behavior.
  • Full client ESLint and TypeScript typechecking passed; npm run build:protoFleet passed the production Vite build.
  • The full local unit run completed 4,013 tests successfully; one unrelated QR/WASM suite could not load through this worktree's symlinked node_modules path and is left to the normal CI checkout.
  • Pre-commit formatting and pre-push typecheck hooks passed.
  • Real systemd/rootful-Docker activation is intentionally covered by the preceding host PRs rather than 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 (419b58d216dc3686f35335eff1fb838b3463d331...f56f6c164da514bdeba61fb17ec70bf6fb60a89d, exact PR three-dot diff)
  • Model: gpt-5.6-sol

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


Review Summary

Overall Risk: MEDIUM

Findings

[MEDIUM] Unknown protobuf phases can lock recovery indefinitely

  • Category: Protobuf
  • Location: client/src/protoFleet/features/updates/api/useUpgradeOperation.ts:102
  • Description: Every phase other than SUCCEEDED or FAILED is considered active, while only UNSPECIFIED enters bounded reconciliation. Proto3 can preserve an enum value unknown to an older client. After upgrading to a newer backend that introduces another phase, the already-loaded client will therefore treat that value as ordinary progress rather than an unknown state.
  • Impact: A new terminal or recovery phase can leave the old client polling every two seconds, displaying “Starting,” and permanently locking the manual installer and release-channel controls. This can strand an operator precisely when upgrade recovery is needed.
  • Recommendation: Use an explicit allowlist of known active phases. Route UNSPECIFIED and every unrecognized numeric value through the bounded unknown-state reconciliation flow, retaining the overlap protection while eventually offering the explicit host-confirmed fallback.

Notes

The authoritative diff applied cleanly in reverse against the pinned commit. The added tests cover UNSPECIFIED, but not an arbitrary forward-compatible numeric enum value. Targeted tests could not be executed because dependencies were unavailable locally and registry access was restricted.


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 df405fc to 14a80be Compare August 8, 2026 05:50
@mcharles-square
mcharles-square marked this pull request as ready for review August 8, 2026 05:55
@mcharles-square
mcharles-square requested a review from a team as a code owner August 8, 2026 05:55
Copilot AI lite review requested due to automatic review settings August 8, 2026 05:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the operator-facing, one-click upgrade workflow to ProtoFleet’s Settings → Updates page, integrating the newly available backend capability and durable upgrade operation status into a route-owned UX (confirmation, progress, recovery, and explicit manual fallback).

Changes:

  • Introduces a useUpgradeOperation hook to trigger upgrades, poll durable status without overlap, and recover/lock state across expected restarts.
  • Adds UpgradeOperationModal to guide operators through confirmation, RC warnings, progress/reconnect, failure recovery details, and success reload.
  • Extends the Updates settings page to surface capability-gated one-click actions, reconcile durable operations vs. newer offers, and lock competing controls appropriately.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
docs/plans/archive/2026-07-29-one-click-upgrade-executor-plan.md Archives the completed plan and documents final boundaries/ownership for the one-click executor workflow.
client/src/protoFleet/features/updates/copyInstallCommand.ts Updates helper comment to reflect Settings-owned manual fallback usage.
client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Adds upgrade lifecycle hook: trigger, bounded reconciliation, non-overlapping polling, and session recovery.
client/src/protoFleet/features/updates/api/useUpgradeOperation.test.tsx Adds focused unit tests for the upgrade operation hook behaviors (recovery, reconciliation, cadence, acknowledgements).
client/src/protoFleet/features/settings/components/UpgradeOperationModal.tsx Implements modal UX for confirmation/progress/failure/success/manual unlock flows.
client/src/protoFleet/features/settings/components/UpgradeOperationModal.test.tsx Adds modal behavior and accessibility assertions for the various states and actions.
client/src/protoFleet/features/settings/components/Updates.tsx Wires one-click upgrade into Settings → Updates, including capability gating, locking, and durable status reconciliation.
client/src/protoFleet/features/settings/components/Updates.test.tsx Extends Settings Updates integration tests for one-click upgrade states and permission revocation handling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts
Comment thread client/src/protoFleet/features/settings/components/Updates.test.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 14a80be769

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 789da4caf2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cfab18509e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/settings/components/Updates.tsx
Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81d998aa06

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 33cc70a6c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9fc5722fce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/settings/components/Updates.tsx Outdated
@mcharles-square

Copy link
Copy Markdown
Collaborator Author

🤖 Addressed the current Codex Security Review finding in a060c5f. Ambiguous no-ID reconciliation now accepts only a target-matching SUCCEEDED operation, so a completed upgrade is recovered and prompts reload; same-target failures still require exact operation-ID correlation and cannot unlock competing install controls. Added coverage where TriggerUpgrade loses its response and the first subsequent durable status is SUCCEEDED.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a060c5f3cb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cdc1a5fec3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/settings/components/Updates.tsx
Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bad5e6e0f5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated
Comment thread client/src/protoFleet/features/settings/components/Updates.tsx

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 78375356e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated
Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bbf954ebef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts
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.

2 participants