Skip to content

feat(client): monitor active firmware updates from the Firmware page - #1021

Draft
rl-block wants to merge 1 commit into
rollout/02b-release-channels-uifrom
rollout/03a-active-updates-ui
Draft

feat(client): monitor active firmware updates from the Firmware page#1021
rl-block wants to merge 1 commit into
rollout/02b-release-channels-uifrom
rollout/03a-active-updates-ui

Conversation

@rl-block

@rl-block rl-block commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Reviewable diff: +1293/-3 across 9 files (excludes generated, test, story and fixture files).

Summary

Lets operators watch and steer updates in flight. Every active rollout gets a banner above the Firmware tabs; opening one shows the update's state and stage, the actions available (Continue, Pause / Resume, Cancel remaining, Roll back, Retry failed), review and failure callouts, scope and threshold stats, a progress bar and the telemetry evidence the auto-continue gate saw. A miners modal drills into per-miner phase, IP, version and telemetry with a failed-only filter, and the manage view gains a History button listing a channel's past rollouts with View and Roll back.

Stack. #1014 (merged: API contract) -> #1015 -> #1016 -> #1017 (rollout engine) -> #1018 -> #1019 (client data hook) -> #1020 (Release Channels tab) -> #1021 (this PR) -> #1022 (header pill and activity log) -> #1023 (E2E). Diff is relative to #1020. Upstream context: Rollout.state, stage, evidence and per-device phase semantics from #1017; the rolloutStatus adapter and rollout actions from #1019; Firmware.tsx / ReleaseChannelsTab structure from #1020. Out of scope: the header pill and activity-feed labels (#1022); E2E (#1023).

How it works

Firmware.tsx mounts ActiveUpdatesMonitor above the tabs with the same useReleaseChannels instance the tab uses. The monitor filters rollouts to active ones and renders ActiveUpdateBanners — one callout per rollout with activeUpdateSummary ("74 of 87 miners updated, 2 failed, Batch 5 of 6") and a tone that escalates when the rollout needs attention (awaiting review, failed miners, paused). The monitor owns the detail modal, the cancel and rollback confirmations, and two request channels: MonitorRequest (the history modal asks it to open a rollout or start a rollback) and onManageChannel (the detail modal's Manage action deep-links into the channels tab on that channel).

RolloutDetailModal reads everything from the Rollout: header with channel, model, target version and rolloutStageLabel; an action row whose buttons depend on state (Continue only when awaiting review, Pause/Resume when active, Cancel remaining while anything is queued, Roll back when a previous version exists, Retry failed when failures exist); callouts for failed miners, a review gate with the hold reason, and paused; stats (scope summary, method and pacing, thresholds, target version); CompositionBar progress from progressSegments; and an evidence strip showing hashrate / efficiency / temperature / new-error deltas against baseline with a pass or hold marker per threshold. "View miners" opens RolloutMinersModal, which fetches the rollout's devices through the paged ListRolloutDevices when it opens (and again on each poll while open) and shows a table with phase chip, batch, IP, reported version, attempts, last error and current telemetry, filterable to failed miners.

ChannelHistoryModal (from the manage view's History button) lists the channel's rollouts newest first with rolloutOutcomeLabel, model, firmware, progress and started/finished times; View hands off to the monitor's detail modal. "Roll back to " appears on an entry when the assignment that was in place before it differs from the current one, and asks the monitor to confirm and call rollbackFirmware for that entry — the server then restores that earlier assignment.

Diagrams

flowchart TD
    F["Firmware.tsx"] --> Mon["ActiveUpdatesMonitor: active rollouts, owns detail + confirmations"]
    F --> Tab["ReleaseChannelsTab (#1020)"]
    Mon --> B["ActiveUpdateBanners: one callout per active rollout, activeUpdateSummary"]
    B --> D["RolloutDetailModal: state, actions, callouts, stats, progress, evidence"]
    D --> Mi["RolloutMinersModal: per-miner phase, IP, version, attempts, telemetry, failed filter"]
    D --> Act["continue / pause / resume / cancel / rollback / retryFailed (#1019)"]
    D --> Manage["Manage -> onManageChannel -> tab opens that channel"]
    Tab --> Hist["ChannelHistoryModal: past rollouts, View / Roll back"]
    Hist --> Mon
Loading
sequenceDiagram
    participant O as Operator
    participant Mon as ActiveUpdatesMonitor
    participant H as useReleaseChannels
    participant S as RolloutService
    O->>Mon: click banner
    Mon->>Mon: open RolloutDetailModal(rollout)
    O->>Mon: Cancel remaining
    Mon->>O: confirm dialog
    O->>Mon: confirm
    Mon->>H: cancelRollout(id)
    H->>S: CancelRollout
    H->>S: ListRollouts / ListReleaseChannels (refresh)
    S-->>H: rollout canceled, updated miners kept
    H-->>Mon: new rollouts
    Mon->>O: banner disappears, history shows Canceled
Loading

Areas of the code involved

Area / file What changed Why it matters for review
.../ReleaseChannels/ActiveUpdatesMonitor.tsx (new) Active filter, banner list, detail modal state, cancel / rollback confirmations, MonitorRequest and manage deep-link plumbing Orchestration; check that requests are cleared after handling so a modal cannot reopen on the next poll
.../ReleaseChannels/ActiveUpdateBanners.tsx (new) Callout per rollout with summary and attention tone Presentational
.../ReleaseChannels/RolloutDetailModal.tsx (new) State-dependent action row, callouts, stats, progress, evidence strip, View miners, Manage Largest file; the action-visibility rules must match the server's preconditions (#1017) or the user gets errors instead of hidden buttons
.../ReleaseChannels/RolloutMinersModal.tsx (new) Device table with failed-only filter, fetched via listRolloutDevices Only consumer of the paged device list; banners and the detail modal use summary counts
.../ReleaseChannels/ChannelHistoryModal.tsx (new) Rollout list with View / Roll back "Roll back to X" is offered on the entry that replaced X, when X is not the current assignment (matches the server's restore-previous semantics)
Firmware.tsx, ReleaseChannelsTab.tsx, ReleaseChannelManageView.tsx Mount the monitor; manage-request remount; History button and modal wiring Small wiring diffs
rolloutStatus.ts activeUpdateSummary Shared with the header pill in #1022
*.stories.tsx (2 new), rolloutStatus.test.ts Banner and detail stories; summary test story / test — skip

Key technical decisions & trade-offs

  • One monitor above the tabs owns every rollout modal, and the history modal asks it via MonitorRequest rather than opening its own detail or rollback dialog, so there is a single place where destructive actions are confirmed.
  • Action buttons are derived from server state, hidden when the server would refuse them, instead of always shown and failing; the derivation lives next to rolloutStatus predicates so it tracks the domain rules.
  • Manage deep-link remounts the channels tab (keyed by request sequence) instead of threading selection state through it, which keeps ReleaseChannelsTab self-contained.
  • Evidence is displayed as the server computed it (Rollout.evidence), not recomputed client-side from device telemetry, so the UI shows exactly what the gate decided on.
  • Cancel and Roll back require confirmation; Continue, Pause and Retry do not, mirroring which actions are hard to undo.
  • Progress everywhere comes from summary counts; only the miners drill-down fetches device pages, so the banners, detail and history stay cheap regardless of fleet size.

Contract alignment (after the #1014 merge)

#1014 merged on 2026-09-08 as 74454ed9. This stack was first cut against the contract of 2026-09-04; on 2026-09-08 every PR was rebased onto main and reworked to the merged contract, so each one is again one commit above its parent and green on its own. Head ab8fea567.

This PR implements: Active-update banners, update detail with actions and the evidence strip (aggregates with sample counts, optional changes), miners drill-down, channel history: rollback is offered while the rollout is at its pair's current assignment generation and reverses the lineage — restoring the previous version or clearing the firmware for a first assignment.

Implementation notes:

  • The history modal still derives entries from rollouts; the events feed will replace that when its slice lands.

Deferred to follow-up slices (not in this stack): delegated control (ROLLOUT_METHOD_DELEGATED, AdvanceRollout, SkipRolloutDevices, CompleteRollout, WAITING_FOR_CONTROLLER, controller_timeout_seconds) and the events feed (ListRolloutEvents, RolloutEvent, RolloutActor history). The schema, behavior, error reasons, permission entries and enum vocabulary for both are already in place; the handler answers those RPCs with Unimplemented and refuses the DELEGATED method until the slices land.

Testing & validation

  • vitest run for features/settings/components: the new activeUpdateSummary case plus the existing suites pass; the two SchedulePreview failures are locale-dependent and identical on main.
  • Storybook stories: banners (single, several, needs attention) and detail modal (in progress, awaiting review with evidence, paused, completed with failures).
  • tsc --noEmit, eslint --max-warnings 0 clean.
  • Not covered here: component tests for the detail modal's action visibility (exercised in test(e2e): cover release channels end to end #1023's pilot, cancel and rollback scenarios).

@github-actions

github-actions Bot commented Sep 4, 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 (cd3effc525c98ad6b2dcfc373cbbc956badd13e1...6fc784616e73751d17ab04b39f55e0b93590ea15, exact PR three-dot diff)
  • Model: gpt-5.6-sol

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


Review Summary

Overall Risk: HIGH

Findings

[HIGH] Automated review incomplete

  • Category: Other
  • Description: The automated review produced no usable result for cd3effc525c98ad6b2dcfc373cbbc956badd13e1...6fc784616e73751d17ab04b39f55e0b93590ea15 (workflow run 34180588206; reason: codex-job-timeout, elapsed: unknown, budget: 9 minutes).
  • Impact: The pull request has not received complete automated security, correctness, and reliability analysis.
  • Recommendation: Require human review before merging. Do not treat this result as approval-free or low risk.

Notes

Human review is required because the bounded automated review was incomplete.


Generated by Codex Security Review |
Triggered by: @rl-block |
Review workflow run

Active-update banners, the full-screen update detail with lifecycle actions
and the telemetry evidence strip, the miners drill-down and the channel
history modal, on the merged contract: rollback is offered while the rollout
is still at its pair's current assignment generation and reverses the
lineage (restoring the previous version, or clearing the firmware for a first
assignment); evidence reads the aggregates with their sample counts and the
optional change fields; rollouts are matched to their group by the folded
manufacturer/model pair key.
@rl-block
rl-block force-pushed the rollout/03a-active-updates-ui branch from 6fc7846 to ab8fea5 Compare September 8, 2026 03:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client 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