Skip to content

feat(rollouts): deployment-plugin parity - #1625

Merged
hisco merged 12 commits into
skyhook-io:mainfrom
jfillman:feature/rollouts-deployment-plugin
Sep 15, 2026
Merged

hisco merged 12 commits into
skyhook-io:mainfrom
jfillman:feature/rollouts-deployment-plugin

Conversation

@jfillman

@jfillman jfillman commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Brings Radar's Argo Rollouts support up to parity with the kubectl-argo-rollouts/Argo CD UI extension's own resource coverage:

  • Backend: new endpoint for full AnalysisRun history (not just the current run) for a Rollout.
  • AnalysisTemplate / ClusterAnalysisTemplate detail renderer: metric definitions, args, and provider config.
  • Experiment detail renderer: templates, weights, and status.
  • Rollout detail view: step timeline, ReplicaSet progression, and AnalysisRun history — the same "what's this rollout actually doing right now" story the plugin's own CLI/UI tells, inline in Radar.
  • Docs updated for the new views.

Test plan

  • go test ./...
  • make tsc
  • npx vitest run (k8s-ui)

🤖 Generated with Claude Code


Note

Medium Risk
Adds a namespace-scoped AnalysisRun list API and richer Rollout UI wiring; risk is moderate due to RBAC boundaries and potential list cost on busy namespaces, but changes are mostly read-only presentation.

Overview
Expands Argo Rollouts coverage so Radar matches the kubectl/Argo CD plugin story for progressive delivery visibility and related CRDs.

Rollout detail now shows a connected canary step or derived blue-green phase timeline (inline step analysis status and links to AnalysisTemplates), a read-only ReplicaSet → pod progression (reusing existing workload revision/pod APIs), and an AnalysisRun history list beyond the four active status slots.

Backend: GET /api/rollouts/{ns}/{name}/analysisruns lists owned AnalysisRuns (phase, trigger, metric counts), gated on list AnalysisRuns RBAC separately from Rollout patch capabilities.

New detail renderers for AnalysisTemplate / ClusterAnalysisTemplate (metrics, providers, args) and Argo Experiment (templates, analyses, status), plus resource-browser columns and dispatch guards so Kubeflow’s unrelated Experiment CRD is not mis-rendered.

Docs and tests updated for the new views and listing behavior.

Reviewed by Cursor Bugbot for commit 27528ff. Bugbot is set up for automated code reviews on this repo. Configure here.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Expand Argo Rollouts visibility and AnalysisRun history

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Adds RBAC-aware full AnalysisRun history for each Rollout.
• Adds rollout timelines, ReplicaSet progression, and richer analysis resource renderers.
• Documents expanded Argo Rollouts coverage and validates backend summarization.
Diagram

graph TD
  DETAIL["Rollout Detail"] --> HOOKS["API Hooks"] --> HANDLER["Rollout Handler"] --> SERVICE["Rollouts Package"] --> K8S[("Kubernetes API")]
  HOOKS --> RENDERERS["Shared Renderers"] --> VIEWS["Progression Views"]
  DISPATCH["Resource Dispatch"] --> RENDERERS
Loading
High-Level Assessment

The chosen approach is appropriate: a dedicated RBAC-aware endpoint safely exposes complete AnalysisRun history, while existing workload revision and pod APIs are reused rather than duplicated. Client-side composition keeps presentation concerns in the UI, and specialized renderers fit the established resource-dispatch architecture.

Files changed (18) +1125 / -54

Enhancement (13) +1019 / -46
rollouts_handlers.goServe RBAC-aware Rollout AnalysisRun history +46/-0

Serve RBAC-aware Rollout AnalysisRun history

• Adds a connected-cluster handler that verifies namespace-level AnalysisRun list permission and returns summarized history. Maps Kubernetes not-found and forbidden errors to appropriate HTTP responses.

internal/server/rollouts_handlers.go

server.goRegister the AnalysisRun history route +1/-0

Register the AnalysisRun history route

• Registers GET '/rollouts/{namespace}/{name}/analysisruns' alongside existing Rollout capability and operation routes.

internal/server/server.go

ResourcesView.tsxAdd curated columns for rollout analysis resources +36/-0

Add curated columns for rollout analysis resources

• Defines list columns for AnalysisTemplate, ClusterAnalysisTemplate, and Experiment resources. Adds metric-count rendering and assigns the new resource kinds to the Argo Rollouts column group.

packages/k8s-ui/src/components/resources/ResourcesView.tsx

AnalysisTemplateRenderer.tsxRender AnalysisTemplate metric definitions and arguments +149/-0

Render AnalysisTemplate metric definitions and arguments

• Adds a shared detail renderer for namespaced and cluster analysis templates. It displays metric conditions, limits, provider identity, selected provider configuration, and template arguments.

packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx

ExperimentRenderer.tsxRender Experiment configuration and live status +169/-0

Render Experiment configuration and live status

• Adds Experiment status, duration, owner, workload-template replicas and weights, analysis references, AnalysisRun links, failures, and conditions. Navigation connects related Rollouts, templates, and runs.

packages/k8s-ui/src/components/resources/renderers/ExperimentRenderer.tsx

RolloutRenderer.tsxExpand Rollout progression and history details +177/-44

Expand Rollout progression and history details

• Extends the Rollout renderer with full AnalysisRun history, canary and blue-green timelines, ReplicaSet and pod progression, and Experiment navigation. Adds helpers for template references and derived blue-green phases.

packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx

index.tsExport new analysis resource renderers +2/-0

Export new analysis resource renderers

• Exports the AnalysisTemplate and Experiment renderers through the shared renderer entry point.

packages/k8s-ui/src/components/resources/renderers/index.ts

CanaryStepTimeline.tsxAdd connected canary and blue-green timelines +167/-0

Add connected canary and blue-green timelines

• Introduces reusable vertical progression timelines with completed, current, pending, and analysis-result states. Canary analysis steps also link to referenced namespaced or cluster templates.

packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx

ReplicaSetProgression.tsxAdd expandable ReplicaSet and pod progression +116/-0

Add expandable ReplicaSet and pod progression

• Displays Rollout revisions newest-first with role badges, image tags, replica counts, and age. Each revision can expand to show associated pod health, phase, restart count, and navigation.

packages/k8s-ui/src/components/resources/renderers/rollout/ReplicaSetProgression.tsx

ResourceRendererDispatch.tsxDispatch specialized analysis and Experiment renderers +5/-1

Dispatch specialized analysis and Experiment renderers

• Recognizes AnalysisTemplate, ClusterAnalysisTemplate, and Experiment as supported resource kinds. Routes them to their new specialized detail renderers.

packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx

analysisruns.goList and summarize Rollout-owned AnalysisRuns +112/-0

List and summarize Rollout-owned AnalysisRuns

• Adds dynamic-client discovery of all AnalysisRuns owned by a Rollout, sorted newest-first. Summaries include trigger, step index, phase, message, and metric verdict counts excluding dry-run results.

pkg/rollouts/analysisruns.go

client.tsAdd the Rollout AnalysisRun history query +25/-0

Add the Rollout AnalysisRun history query

• Defines the AnalysisRun summary contract and a cached query hook for the new Rollout history endpoint.

web/src/api/client.ts

RolloutRenderer.tsxSupply history, revisions, and pods to Rollout views +14/-1

Supply history, revisions, and pods to Rollout views

• Fetches complete AnalysisRun history through the new endpoint and reuses existing workload revision and pod hooks. Passes all three datasets into the shared Rollout renderer.

web/src/components/resources/renderers/RolloutRenderer.tsx

Tests (4) +94 / -4
curated-column-ownership.test.tsUpdate curated-column ownership expectations +3/-3

Update curated-column ownership expectations

• Adjusts extraction and ownership totals to account for the three newly curated Argo Rollouts resource kinds.

packages/k8s-ui/src/components/resources/curated-column-ownership.test.ts

badge-no-handrolled.test.tsxRemove Rollout renderer from badge exception baseline +1/-1

Remove Rollout renderer from badge exception baseline

• Updates the badge-style guard after the Rollout renderer switched away from its previous hand-rolled inactive badge styling.

packages/k8s-ui/src/components/resources/renderers/badge-no-handrolled.test.tsx

analysisruns_test.goTest AnalysisRun ownership, sorting, and metrics +88/-0

Test AnalysisRun ownership, sorting, and metrics

• Verifies foreign runs are excluded, owned runs are returned newest-first, labels are parsed, and dry-run metrics do not affect verdict counts.

pkg/rollouts/analysisruns_test.go

operations_test.goRegister AnalysisRun types in rollout test clients +2/-0

Register AnalysisRun types in rollout test clients

• Extends the fake dynamic-client scheme with AnalysisRun and AnalysisRunList types for the new history tests.

pkg/rollouts/operations_test.go

Documentation (1) +12 / -4
integrations.mdDocument expanded Argo Rollouts resource views +12/-4

Document expanded Argo Rollouts resource views

• Marks AnalysisTemplate, ClusterAnalysisTemplate, and Experiment as fully rendered. Documents rollout timelines, ReplicaSet and pod progression, complete AnalysisRun history, RBAC behavior, and unchanged topology bounds.

docs/integrations.md

@qodo-code-review

qodo-code-review Bot commented Sep 3, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Katib Experiments use Argo renderer ✓ Resolved 🐞 Bug ≡ Correctness
Description
ResourceRendererDispatch treats every experiments resource as an Argo Rollouts Experiment and
suppresses the generic renderer, even when its API group is kubeflow.org. Katib Experiments
consequently show an Argo-specific mostly-empty status view instead of their actual resource
details.
Code

packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[771]

+        {kind === 'experiments' && <ExperimentRenderer data={data} onNavigate={onNavigate} />}
Relevance

●● Moderate

The API-group collision is plausible and consequential, but no historical precedent confirms this
dispatch policy.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The dispatch table adds experiments to KNOWN_KINDS and invokes ExperimentRenderer without an
API-group predicate. Existing dispatch logic suppresses GenericRenderer for known kinds unless an
explicit collision fallthrough applies, while Kubeflow documents a distinct kubeflow.org/v1beta1
resource with kind Experiment and a different spec/status schema.

packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[663-680]
packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[698-698]
packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[770-771]
packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[963-963]
🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.: 🌐 Kubeflow documents Katib resources with apiVersion: kubeflow.org/v1beta1 and kind: Experiment, whose hyperparameter-tuning schema differs from Argo Rollouts Experiment.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Experiment renderer is selected solely from the `experiments` plural. This collides with Kubeflow Katib's `kubeflow.org/v1beta1` Experiment resource and suppresses its generic renderer.
## Issue Context
Follow the existing group-gated-kind pattern: render `ExperimentRenderer` only for `argoproj.io` resources, and ensure foreign Experiment resources fall through to `GenericRenderer`. Apply equivalent group checks to the newly registered AnalysisTemplate kinds where appropriate.
## Fix Focus Areas
- packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[431-431]
- packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[663-680]
- packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[770-771]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Renderers bypass Badge component ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The new renderers construct status and provider badges with ` plus badge/badge-sm` and tone
classes instead of the shared ` component. This bypasses the required semantic severity or kind`
appearance API.
Code

packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[R103-105]

+                    <span className="font-mono text-sm text-theme-text-primary">{metric.name}</span>
+                    {provider && <span className="badge-sm status-neutral">{providerLabel(provider.name)}</span>}
+                  </div>
Relevance

●●● Strong

Recent renderer precedent accepts replacing hard-coded badge styling with shared semantic Badge
APIs.

PR-#1018
PR-#1432

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 3036677 requires badge-like UI to use `` with semantic props. The cited additions
instead use spans with classes such as badge, badge-sm, status-neutral, and dynamically
selected status tones.

Rule 3036677: Use Badge components instead of hard-coded badge color strings
packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[103-105]
packages/k8s-ui/src/components/resources/renderers/ExperimentRenderer.tsx[60-62]
packages/k8s-ui/src/components/resources/renderers/ExperimentRenderer.tsx[93-96]
packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[704-706]
packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[89-97]
packages/k8s-ui/src/components/resources/renderers/rollout/ReplicaSetProgression.tsx[79-83]
packages/k8s-ui/src/components/resources/renderers/rollout/ReplicaSetProgression.tsx[103-103]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New badge-like status, provider, role, and phase indicators are hand-built from spans and appearance classes.
## Issue Context
Use the shared `Badge` component and select appearance through its `severity` or `kind` prop rather than explicit badge/tone classes.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[103-105]
- packages/k8s-ui/src/components/resources/renderers/ExperimentRenderer.tsx[60-62]
- packages/k8s-ui/src/components/resources/renderers/ExperimentRenderer.tsx[93-96]
- packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[704-706]
- packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[89-97]
- packages/k8s-ui/src/components/resources/renderers/rollout/ReplicaSetProgression.tsx[79-83]
- packages/k8s-ui/src/components/resources/renderers/rollout/ReplicaSetProgression.tsx[103-103]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. analysisTone duplicates health vocabulary ✓ Resolved 📘 Rule violation ≡ Correctness
Description
The timeline introduces the overlapping health-like values ok, warning, and fail rather than
the canonical HealthLevel tones. This creates a parallel status vocabulary and requires ad-hoc
translation logic.
Code

packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[R24-27]

+function stepDotTone(state: StepState, analysisTone?: 'ok' | 'warning' | 'fail') {
+  if (state === 'current' && analysisTone) {
+    if (analysisTone === 'fail') return 'bg-red-500/25 text-red-500 dark:bg-red-500/35'
+    if (analysisTone === 'warning') return 'bg-amber-500/25 text-amber-600 dark:text-amber-400 dark:bg-amber-500/35'
Relevance

●●● Strong

The finding directly enforces the repository's stated canonical status vocabulary requirement.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 3036741 limits health tone values to healthy, degraded, alert, unhealthy,
neutral, and unknown. The added analysisTone type instead defines and propagates ok,
warning, and fail.

Rule 3036741: Use only the standard HealthLevel tones and normalize external values
packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[24-45]
packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[69-77]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`analysisTone` defines a parallel health vocabulary using `ok`, `warning`, and `fail`.
## Issue Context
Use only canonical HealthLevel values and normalize AnalysisRun phases through a central mapper before rendering.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[24-45]
- packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[69-77]
- packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[89-97]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Content sections default collapsed ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
Several new non-empty sections are collapsed or omit defaultExpanded, including Arguments,
Experiment Status, AnalysisRun History, and ReplicaSets. None is marked low-priority, so each must
explicitly enable expansion by default.
Code

packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[R130-132]

+      {args.length > 0 && (
+        <Section title={`Arguments (${args.length})`} icon={Server} defaultExpanded={false}>
+          <PropertyList>
Relevance

●●● Strong

Explicit expansion behavior is deterministic and aligns with recent accepted renderer consistency
fixes.

PR-#1446

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 3036709 requires every non-empty, non-low-priority renderer section to explicitly
set defaultExpanded to true. The cited sections either set it to false or omit it entirely while
rendering substantive content.

Rule 3036709: Renderer sections with content must explicitly set defaultExpanded to true
packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[130-141]
packages/k8s-ui/src/components/resources/renderers/ExperimentRenderer.tsx[60-84]
packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[701-736]
packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[760-769]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New sections with substantive content are collapsed or omit the required explicit expanded state.
## Issue Context
Set `defaultExpanded={true}` unless a section is explicitly marked low-priority using a supported priority prop.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[130-141]
- packages/k8s-ui/src/components/resources/renderers/ExperimentRenderer.tsx[60-84]
- packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[701-736]
- packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[760-769]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (5)
5. revisions comment cites history ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The revisions prop comment describes the hooks as already-shipped, embedding implementation
history in a code comment. Code comments must explain current intent or constraints without
referring to change or release history.
Code

packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[R66-69]

+  // Host-fetched — the Rollout's ReplicaSet revision history + its pods,
+  // already-shipped generic workload hooks (useWorkloadRevisions/
+  // useWorkloadPods), joined client-side by the host. Read-only here; the
+  // rollback action stays exclusively in the existing history dialog.
Relevance

●●● Strong

Recent precedent explicitly accepted rewriting comments that reference prior implementation history.

PR-#1614

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 3036538 prohibits explicit change or PR history in code comments. The added comment
calls the workload hooks already-shipped, which is historical rather than current behavioral
context.

Rule 3036538: Disallow references to tickets or PR history in code comments
packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[66-69]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `revisions` prop comment references implementation history with `already-shipped`.
## Issue Context
Describe the hooks and client-side join as current behavior without referring to when they shipped.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[66-69]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Visual comments restate JSX ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
Comments such as Canary Steps visual, BlueGreen progression visual, and ReplicaSet progression
merely label the immediately following named sections. They add no rationale or hidden constraint
and can be removed without reducing understanding.
Code

packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[739]

+      {/* Canary Steps visual */}
Relevance

●●● Strong

Removing comments that merely label JSX is a trivial maintainability fix; no contrary precedent
appeared.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 3036542 disallows comments that only translate obvious code behavior into prose.
Each cited comment repeats the title or component name directly below it.

Rule 3036542: Avoid explanatory comments that restate obvious code behavior
packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[739-759]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Several comments simply restate the section rendered immediately below them.
## Issue Context
The `Section`, `CanaryStepTimeline`, `BlueGreenTimeline`, and `ReplicaSetProgression` names already communicate the behavior.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx[739-759]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. New kinds lack status dispatch ✗ Dismissed 📘 Rule violation ≡ Correctness
Description
The PR registers AnalysisTemplate, ClusterAnalysisTemplate, and Experiment renderers and adds them
to KNOWN_KINDS, but getResourceStatus() has no branches for these kinds. Experiment therefore
loses its available status.phase, while all three violate the required synchronized registration
contract.
Code

packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[R770-771]

+        {(kind === 'analysistemplates' || kind === 'clusteranalysistemplates') && <AnalysisTemplateRenderer data={data} />}
+        {kind === 'experiments' && <ExperimentRenderer data={data} onNavigate={onNavigate} />}
Relevance

●●● Strong

Missing synchronized status registration is a concrete correctness gap in the new resource
integration.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 3036694 requires each new kind to appear in the renderer registry, KNOWN_KINDS,
main dispatch, and getResourceStatus(). The new kinds appear in the first dispatch locations,
while the status function proceeds from analysisruns directly to workflows without any of the
three new kinds.

Rule 3036694: Register new Kubernetes resource renderers in both k8s-ui and shared dispatch files
packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[428-431]
packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[767-771]
packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[1087-1093]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New renderer kinds are registered without corresponding `getResourceStatus()` handling.
## Issue Context
Add status-resolution branches for `analysistemplates`, `clusteranalysistemplates`, and `experiments`. Use the Experiment phase and an appropriate stable status for template resources rather than falling through implicitly.
## Fix Focus Areas
- packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[428-431]
- packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[767-771]
- packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx[1012-1092]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Provider model lacks discrimination ✗ Dismissed 📘 Rule violation ⚙ Maintainability
Description
Provider parsing returns an unconstrained { name: string; details: any }, forcing a non-exhaustive
string switch with a fallback. Provider-specific required fields should be represented by an
exhaustive discriminated union.
Code

packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[R15-18]

+function detectProvider(metric: any): { name: string; details: any } | null {
+  const provider = metric?.provider
+  if (!provider) return null
+  for (const key of PROVIDER_KEYS) {
Relevance

●● Moderate

Discriminated-union requirement is explicit, but no closely matching historical precedent was found.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 3038619 requires provider-specific models to be discriminated unions and selector
switches to be exhaustive. The new model uses name: string, details: any, and a `default: return
null` branch.

Rule 3038619: Prefer discriminated unions over optional field bags to avoid non-null assertions
packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[8-23]
packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[37-82]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The parsed provider model uses an arbitrary string and `any` details, so provider-specific fields are not type-safe and the rendering switch is non-exhaustive.
## Issue Context
Create a union keyed by the provider name, with the required details shape for each supported provider. Make rendering exhaustive without a generic trailing fallback for recognized providers.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[8-23]
- packages/k8s-ui/src/components/resources/renderers/AnalysisTemplateRenderer.tsx[37-82]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Timeline uses raw backgrounds ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
stepDotTone introduces raw red, amber, emerald, and blue Tailwind background utilities. Background
colors must use approved theme tokens or shared semantic components unless a documented design
exception applies.
Code

packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[R25-28]

+  if (state === 'current' && analysisTone) {
+    if (analysisTone === 'fail') return 'bg-red-500/25 text-red-500 dark:bg-red-500/35'
+    if (analysisTone === 'warning') return 'bg-amber-500/25 text-amber-600 dark:text-amber-400 dark:bg-amber-500/35'
+  }
Relevance

●● Moderate

Theme-token guidance supports acceptance, but recent same-day rejection of raw palette styling makes
team behavior uncertain.

PR-#1614

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 3036653 permits only bg-theme-base, bg-theme-surface, bg-theme-elevated, or
bg-theme-hover background utilities absent a documented exception. stepDotTone returns multiple
raw palette background classes without such an exception.

Rule 3036653: Use theme background tokens instead of hardcoded utility color classes
packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[24-36]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Timeline dots use hardcoded Tailwind palette background classes.
## Issue Context
Replace raw `bg-red-*`, `bg-amber-*`, `bg-emerald-*`, and `bg-blue-*` utilities with approved theme tokens or an existing semantic status component. Preserve light and dark mode behavior.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx[24-36]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can reply 'qodo' on any finding to push back, ask questions, or dig deeper

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx Outdated
Comment thread packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx Outdated
Comment thread packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx Outdated
Comment thread packages/k8s-ui/src/components/resources/renderers/rollout/CanaryStepTimeline.tsx Outdated
Comment thread packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx Outdated
Comment thread packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx Outdated

@cursor cursor 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.

Stale Bugbot comment from a previous run.

Comment thread packages/k8s-ui/src/components/resources/renderers/RolloutRenderer.tsx Outdated
Comment thread packages/k8s-ui/src/components/resources/ResourcesView.tsx Outdated

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e8c2f9f. Configure here.

@hisco hisco 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.

Thanks for this. It closes a real gap, and your replies to the bot round were good judgment, including the two you pushed back on.

I've pushed four commits to your branch rather than sending it back, and merged main in since it had drifted. Your commits are untouched. What changed:

Formatting. The comments inside AnalysisRunSummary split gofmt's struct tag alignment into separate blocks. That was the only thing failing CI. Worth running gofmt -l . locally, go test won't catch it.

The analysis history sat above the live progression. On a paused rollout you scrolled past finished runs to reach the step the rollout is actually on. It's now below the ReplicaSets and collapsed. That one is taste rather than a bug, so say if you'd rather have it back.

A running analysis rendered as a warning. The inline badge on the current step mapped four phases and fell back to the alert tone for everything else, so Running and Pending read as problems. getAnalysisRunStatus and analysisStatusClass already carried the same mapping, so this was a third copy that had drifted. All three now share analysisPhaseLevel.

Also corrected the rollout-type label values in a comment, Argo writes Background rather than BackgroundAnalysis, and gave an Inconclusive Experiment the warning banner the AnalysisRun renderer already uses

jfillman and others added 12 commits September 15, 2026 13:18
Today the only backend AnalysisRun awareness is topology's
activeAnalysisRuns(), deliberately restricted to the Rollout's 4
"currently active" status slots. Adds pkg/rollouts.ListAnalysisRuns,
following revisions.go's exact shape (reuses its unexported ownedBy
helper) to list every AnalysisRun owned by a Rollout, newest first,
with per-run metric pass/fail counts computed the same way
resource-utils.ts's summarizeAnalysisMetrics does (dryRun results
excluded from the tally).

New GET /rollouts/{ns}/{name}/analysisruns handler, gated on listing
AnalysisRuns directly rather than the Rollout's own patch grant —
same reverse-lookup pattern as the RBAC/Policy/Velero/CNPG endpoints
elsewhere in this file's siblings.
…derer

Both kinds were already discovered/cached but fell through to the
generic raw-YAML renderer. New AnalysisTemplateRenderer shows each
metric's provider (Prometheus/Web/Job/Kubernetes/etc.), interval,
count, success/failure conditions, and provider-specific config —
same shape AnalysisRunRenderer already parses for a run's live
results, applied here to the static template definition instead.

Registered in ResourceRendererDispatch (no collision guard needed —
both kind strings are unique across the whole repo) and given curated
table columns (Name, Namespace where applicable, Metrics count, Age).
status.canary.currentExperiment was a bare string with no drill-down
anywhere. New ExperimentRenderer shows spec.templates[] (replicas,
weight) with live status.templateStatuses[] (ready/available counts,
phase), spec.analyses[] with their AnalysisTemplate references and
live status.analysisRuns[] verdicts.

No demo fixture exists for this CRD, so it was verified against a
real Experiment applied directly to the rollouts-demo cluster rather
than an official scenario — which caught a genuine field-name bug:
the live controller's status shape is analysisRuns[]/phase, not the
analysisRunStatuses[]/status shape the initial implementation assumed
from the public docs' examples. Fixed against the real object.
…story

Mirrors kubectl-argo-rollouts and the ArgoCD UI extension's Rollout
view, and closes the three gaps the current renderer had against
them:

- Canary Steps upgraded from a flat status-dot list to a connected
  vertical stepper (CanaryStepTimeline) — same connecting-line visual
  as ConditionsSection. Steps are a strictly linear sequence, so this
  stays a simple top-to-bottom timeline rather than reaching for a
  graph library the way Tekton's DAG needed to. The current step's
  live analysis status (if it has one) now shows inline, and analysis
  steps get clickable links to the AnalysisTemplate/
  ClusterAnalysisTemplate they reference (canaryStepTemplateRefs).
- blueGreen gets an equivalent derived phase list (blueGreenPhases) —
  it has no steps[] array to iterate, so this crosses strategy config
  against live status.blueGreen fields. Verified live against the
  demo fixture's real BlueGreenPause state and fixed a real ordering
  bug: scaleUpPreviewCheckPoint is absent on real Rollouts (a narrow
  field, not a general "preview is up" signal) — "preview scaled up"
  now also treats a recorded pre-promotion analysis, or the Rollout
  having reached any blueGreen pause, as equally valid completion
  evidence, since neither can happen before the preview is scaled.
- New ReplicaSetProgression section: a read-only revision tree
  (Rollout -> ReplicaSet revision -> pods), reusing the already-shipped
  useWorkloadRevisions/useWorkloadPods hooks and revisionRoleBadges()
  from the existing rollback dialog — no new backend endpoint needed,
  the per-pod revisionIdentity hash already joins pods to their
  revision. Rollback itself stays exclusively on the existing dialog.
- New AnalysisRun History subsection surfaces the backend's new
  history endpoint (name, phase, trigger, metrics passing/total),
  alongside the existing 4 "currently active" slots.
- status.canary.currentExperiment is now a nav link to the new
  Experiment renderer instead of a bare string.

Host wrapper (web/) fetches the two new data sources
(useRolloutAnalysisRuns, useWorkloadRevisions/useWorkloadPods) and
passes them down as optional props, keeping packages/k8s-ui pure —
a library consumer that skips the fetch loses only the new sections,
nothing else breaks.

Also removes RolloutRenderer.tsx from badge-no-handrolled.test.tsx's
BASELINE: replacing the old hand-rolled status-dot markup with the
new stepper left it with zero hand-rolled chip colors.
Flips AnalysisTemplate/ClusterAnalysisTemplate/Experiment's Detail
View column to Yes and adds prose for the step timeline, ReplicaSet
progression, and AnalysisRun history sections.
…ueGreen completion detection

Two real bugs in RolloutRenderer.tsx, both confirmed against the real
Argo Rollouts API schema and cross-checked against docs/mcp fixtures:

- canaryStepTemplateRefs assumed a distinct clusterTemplateName field
  name for cluster-scoped refs. The real schema uses ONE field
  (templateName) for both scopes, disambiguated by a separate
  clusterScope boolean — that field never exists in real objects, so
  every ref was always treated as namespaced, and a step referencing a
  ClusterAnalysisTemplate opened the wrong kind. Also extended it to
  handle Experiment spec.analyses[] entries, which carry
  templateName/clusterScope flat on the entry itself rather than
  nested under a templates[] array — previously always returned empty
  for Experiments, so template links never appeared there at all.

- blueGreenPhases required activeSelector === previewSelector to
  consider a Rollout promoted, but Argo Rollouts clears previewSelector
  once there's no active preview to track — a settled, fully-Healthy
  blueGreen commonly has none, so completion could never be detected
  past the narrow just-promoted window. Now also accepts activeSelector
  matching status.currentPodHash (a generic, always-populated field
  naming the newest ReplicaSet) as equally valid completion evidence.

Also removed three comments that only restated the section title
immediately below them, and one that described a dependency as
"already-shipped" instead of just its current behavior.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ral CRD; give it a real status/phase

Two real gaps:

- The experiments render branch and status dispatch had no group
  guard at all — Katib (kubeflow.org) ships its own, unrelated
  Experiment CRD sharing this plural, and got the Argo Rollouts
  Experiment renderer's mostly-empty status view instead of its actual
  resource details. Gated both on argoproj.io, matching every other
  collision guard already in this file (Istio Gateway, CNPG Cluster,
  Kyverno Policy, etc.) and CLAUDE.md's own documented pattern for
  exactly this shape of collision.

- getResourceStatus() had no branch for experiments at all (present
  for analysisruns, missing here), and the Resources table routed the
  Phase column through GenericCell — whose generic phase heuristic
  doesn't recognize 'Successful' (Experiment's actual terminal phase)
  and treats 'Running' as healthy, neither correct for the
  AnalysisPhase vocabulary Experiment actually reports. Both now use
  getAnalysisRunStatus, which already has the right mapping for that
  exact vocabulary (Experiment and AnalysisRun share it) — a new
  ExperimentCell for the table, same pattern as the existing
  AnalysisRunCell, rather than touching the generic heuristic other
  kinds still rely on.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d-hoc classes and a parallel vocabulary

- Metric provider badge (AnalysisTemplate renderer) hand-wrote
  `badge-sm status-neutral` instead of the shared <Badge> component —
  everywhere else in a drawer body (not a table cell, where .status-*
  is the documented exception) uses it directly.

- Arguments, AnalysisRun History, and ReplicaSets sections explicitly
  defaulted to collapsed with real, non-empty, non-low-priority
  content — every other populated section on the same pages already
  relies on Section's own default (expanded). Pod Template stays
  collapsed deliberately — it's not part of this fix; the same raw
  pod-spec dump already collapses by default in the generic
  WorkloadRenderer, a pre-existing, intentional convention.

- CanaryStepTimeline's step-analysis dot/badge used a hand-rolled
  'ok'/'warning'/'fail' vocabulary with hardcoded red/amber Tailwind
  backgrounds, duplicating (and requiring hand-translation back to)
  the canonical HealthLevel tones the badge already used one line
  away. Switched to HealthLevel + the shared healthColors token map
  throughout — same visual states (a failed/inconclusive analysis on
  the current step still gets its own color; a successful one doesn't
  change the dot, matching the original behavior exactly), no parallel
  vocabulary or raw colors left.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…values

The comments interleaved in AnalysisRunSummary split gofmt's struct tag
alignment into separate blocks, so the original spacing no longer matched
what gofmt produces. CI's gofmt check fails on it.

The rollout-type label values in the comment were also wrong. Argo Rollouts
writes Step, Background, PrePromotion and PostPromotion, not the longer
"...Analysis" spellings.
AnalysisRun History rendered above the canary step timeline and the
blue-green progression, so an operator opening a paused rollout scrolled
past finished runs to reach the step it is actually sitting on. That step
is the most decision-relevant thing on the screen.

History now sits below ReplicaSets and starts collapsed. It answers "has
this been flaky before", which is a question you go looking for, not one
you need in front of you mid-rollout.
An Inconclusive phase fell through to status-unknown and showed no banner,
so an Experiment whose analysis matched neither its success nor its failure
condition read as "no information" rather than as something needing a
decision. AnalysisRunRenderer already treats Inconclusive as a warning.

Inconclusive now maps to status-alert and gets a warning banner, matching
that renderer.
The inline badge on the current canary step mapped Successful, Failed,
Error and Inconclusive, then fell back to the alert tone for everything
else. Running and Pending are the usual states while a step is live, so
an analysis that was simply still going read as a warning.

getAnalysisRunStatus and analysisStatusClass already carried the same
phase to tone mapping, so this was a third copy that had drifted. All
three now share analysisPhaseLevel, which also gives an unrecognised
phase the unknown tone rather than alert.
@hisco
hisco force-pushed the feature/rollouts-deployment-plugin branch from 00e36d0 to 27528ff Compare September 15, 2026 10:19
@hisco
hisco merged commit 0c88e53 into skyhook-io:main Sep 15, 2026
9 checks passed
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.

2 participants