Skip to content

Avoid Issues warnings for Crossplane's pause annotation - #2306

Merged
nadaverell merged 3 commits into
mainfrom
fix/paused-reconcile-condition
Oct 26, 2026
Merged

nadaverell merged 3 commits into
mainfrom
fix/paused-reconcile-condition

Conversation

@nadaverell

@nadaverell nadaverell commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Radar adds a reconciliation warning when a Crossplane resource reports Synced=False, ReconcilePaused, even when the operator deliberately paused it with crossplane.io/paused: "true".

Keep that one condition quiet only when the annotation is exactly "true". Continue evaluating other condition types, so a separate Ready=False, Unavailable remains eligible under the usual condition and generation filters. A real Synced=False, ReconcileError still warns despite the annotation. Matching the annotation also covers Crossplane resources with user-defined API groups.

Uses the shared condition-by-condition selector. This PR contains only the pause predicate, focused regression scenarios and integration documentation. Pausing through empty managementPolicies remains a separate scenario. Existing whole-object generation/suspend filters are unchanged. This is an Issues-detection fix: the existing frontend badge can still label the paused state Out of sync, which needs a focused frontend follow-up.

Validation: focused pause regressions, the full internal/issues suite and make build passed on 87197c47bee934f1bf58e8a3f9930bb8a96e6c17. The EKS matrix below used identical detector source. An actual EKS API/informer/HTTP matrix covered 17 synthetic status scenarios × flat/grouped views × three reads, including a stale-generation pause, independent failures, authority, unknown onset and the existing generation gate. Resume/error/recovery/reblock checks converged in one poll each, and unchanged error controls retained their IDs and observation metadata. The real Issues page loaded without page errors, showed independent failures and omitted the pause-only row. Owned test fixtures and local servers were removed afterward.

Visual feature screenshots are skipped because rendering is unchanged. The EKS fixtures prove Radar's real storage/cache/API behavior; no Crossplane-controller or cloud failure was induced. Required CI is green on the final head.

@nadaverell
nadaverell requested a review from hisco as a code owner October 25, 2026 17:35
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

PR Summary by Qodo

Suppress intentional Crossplane pause warnings without hiding failures

🐞 Bug fix 🧊 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

â€Ē Suppress Synced=False/ReconcilePaused warnings only when crossplane.io/paused is exactly
 "true".
â€Ē Continue checking other condition types so actionable failures remain visible.
â€Ē Add regression coverage and document the Issues behavior.
Diagram

graph TD
  A["Watched resource"] --> B["Select false condition"] --> C{"Current and actionable?"} -->|Yes| E{"Explicit pause?"} -->|No| F["Emit issue"]
  C -->|No| D["Skip condition type"] --> B
  E -->|Yes| D
  B -->|None left| G["No issue"]
Loading
High-Level Assessment

Keep the narrow, condition-level annotation check. Suppressing an entire resource would hide independent failures, while matching Crossplane API groups would miss resources with user-defined groups.

Files changed (3) +157 / -12

Bug fix (1) +24 / -12
source_conditions.goSelect actionable conditions after skipping explicit pauses +24/-12

Select actionable conditions after skipping explicit pauses

â€Ē Routes generic and curated condition detection through a selector that skips transient, stale, or explicitly paused conditions by type. It continues searching other types rather than letting a suppressed condition hide an actionable failure.

internal/issues/source_conditions.go

Tests (1) +131 / -0
source_conditions_test.goCover pause matching and independent condition failures +131/-0

Cover pause matching and independent condition failures

â€Ē Adds flat and grouped Issues cases for exact, missing, false, and noncanonical pause annotations, plus failures before and after a paused condition. Also tests stale condition representations, transient suppression, and curated condition selection.

internal/issues/source_conditions_test.go

Documentation (1) +2 / -0
integrations.mdDocument intentional-pause behavior in Issues +2/-0

Document intentional-pause behavior in Issues

â€Ē Clarifies that an explicitly paused Crossplane Synced condition does not produce an Issues warning, while independent failures remain visible.

docs/integrations.md

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) ðŸŽĻ UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Some stale conditions appear current 🐞 Bug ≡ Correctness
Description
FindFalseConditionWithTime reads observedGeneration only as int64, silently turning an
integral float64 value into zero. Dynamic-informer objects can carry that numeric shape, and
findActionableCondition treats zero as an absent generation signal, so an older failure is emitted
without its stale-generation qualification.
Code

pkg/conditions/conditions.go[R122-123]

+					observedGeneration, _ := cond["observedGeneration"].(int64)
+					result := FalseCondition{Type: ct, Reason: r, Message: m, ObservedGeneration: observedGeneration}
Evidence
The generic detector reads unstructured resources from the dynamic provider. The repository
documents that dynamic-informer objects can carry integer fields as float64, while the new assertion
accepts only int64; the selector then treats the resulting zero as current or unqualified.

internal/issues/source_conditions.go[76-112]
internal/k8s/detect.go[2187-2204]
pkg/conditions/conditions.go[119-123]
internal/issues/source_conditions.go[283-291]

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

## Issue description
An integral float64 condition generation from a dynamic informer is read as zero, so stale failures lose their generation qualification.
## Fix Focus Areas
- pkg/conditions/conditions.go[119-123]
- internal/issues/source_conditions.go[283-291]
## Recommended Fix
Parse supported integer representations of `observedGeneration`, including integral float64 values, before applying the generation comparison. Add a regression test using an integral float64 condition generation.

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


2. Rollout issues lose generation context 🐞 Bug ≡ Correctness
Description
findActionableCondition adds the stale-generation qualification to the selected condition's
message, but the Argo Rollout override subsequently replaces that message with one from
argoRolloutFailure. When a Rollout has an older failing health condition and an older definitive
failure condition, its emitted critical issue has no indication that the reported failure predates
the current resource generation.
Code

internal/issues/source_conditions.go[R289-291]

+			if !hasStale {
+				condition.Message = strings.TrimSpace(fmt.Sprintf("Condition was last reported for generation %d; current resource generation is %d. %s", condition.ObservedGeneration, u.GetGeneration(), condition.Message))
+				stale, hasStale = condition, true
Evidence
The new fallback qualifies the selected condition, but the reachable generic Rollout path assigns
issMsg from the separate failure reader afterward. That reader returns the failure's raw message
without a generation comparison.

internal/issues/source_conditions.go[165-202]
internal/issues/source_conditions.go[283-297]
internal/issues/source_conditions.go[647-698]

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 Rollout-specific failure override discards the new stale-generation qualification and does not check the generation of the failure it substitutes.
## Fix Focus Areas
- internal/issues/source_conditions.go[289-291]
- internal/issues/source_conditions.go[181-202]
- internal/issues/source_conditions.go[647-698]
## Recommended Fix
When selecting a definitive Rollout failure, read and compare that failure condition's observed generation with the resource generation, then qualify its emitted message when stale. Add a regression with stale health and definitive failure conditions.

ⓘ 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 type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@nadaverell
nadaverell changed the base branch from fix/actionable-condition-selection to main October 25, 2026 18:01
@nadaverell nadaverell closed this Oct 25, 2026
@nadaverell nadaverell reopened this Oct 25, 2026
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 7dce015

@nadaverell
nadaverell changed the base branch from main to fix/actionable-condition-selection October 25, 2026 18:17
@nadaverell
nadaverell changed the base branch from fix/actionable-condition-selection to main October 26, 2026 00:52
@nadaverell
nadaverell force-pushed the fix/paused-reconcile-condition branch from 7dce015 to 6ed9b98 Compare October 26, 2026 00:52
@nadaverell nadaverell changed the title Keep intentional Crossplane pause out of Issues Avoid Issues warnings for Crossplane's pause annotation Oct 26, 2026
@nadaverell

Copy link
Copy Markdown
Contributor Author

/review

Comment thread pkg/conditions/conditions.go
Comment thread internal/issues/source_conditions.go
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 5975b13

@nadaverell
nadaverell changed the base branch from main to fix/actionable-condition-selection October 26, 2026 01:19
Base automatically changed from fix/actionable-condition-selection to main October 26, 2026 08:29
@nadaverell
nadaverell force-pushed the fix/paused-reconcile-condition branch from 5975b13 to 87197c4 Compare October 26, 2026 08:34
@cursor

cursor Bot commented Oct 26, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@nadaverell
nadaverell force-pushed the fix/paused-reconcile-condition branch from 87197c4 to 749b2e9 Compare October 26, 2026 11:50
@nadaverell
nadaverell merged commit 72fa34f into main Oct 26, 2026
11 checks passed
@nadaverell
nadaverell deleted the fix/paused-reconcile-condition branch October 26, 2026 15:43
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