fix(issues): preserve honest onset provenance - #1390
Open
nadaverell wants to merge 6 commits into
Open
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 04d2b62. Configure here.
This was referenced Aug 9, 2026
nadaverell
added a commit
that referenced
this pull request
Aug 9, 2026
## Summary - detect Gateways that reference a missing GatewayClass after a two-minute reconciliation grace - detect HTTPRoute, GRPCRoute, TCPRoute, and TLSRoute parentRefs that target a missing Gateway - require authoritative cluster or exact-namespace informer coverage before asserting absence - preserve unrelated Gateway controller conditions while deduplicating exact structural echoes, including Envoy Gateway PortNotFound - apply the same authority check to KEDA Rollout scaleTargetRefs so partial caches cannot produce false missing-target issues ## Validation - `make build` - `make test` - `make tsc` - `go test ./internal/issues ./internal/k8s` - `go test ./...` from `pkg/k8score/` - live EKS smoke on `radar-test-nonprod`: grace suppression, both findings present, target creation recovery, and fixture cleanup - Playwright Issues-page smoke with both findings rendered and zero console errors - visual-test skipped: no UI delta ## Stack - stacked on #1391 - #1391 is stacked on #1390 Linear: RAD-346 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes live issue detection for Gateway networking and dynamic-cache “absence” semantics; incorrect authority or dedupe could hide real problems or briefly miss issues during informer sync, but behavior is heavily tested and biased toward silence when coverage is incomplete. > > **Overview** > Extends **Gateway API missing-reference detection** beyond route backend Services: after a **2-minute grace**, it flags **Gateways** with a non-existent `spec.gatewayClassName` and **routes** (`HTTPRoute`, `GRPCRoute`, `TCPRoute`, `TLSRoute`) whose `parentRefs` point at a **missing Gateway** (same- or cross-namespace). **Backend Service / port / ReferenceGrant** checks still require the Service lister; **topology** checks (class + parent) run even when Services aren’t available. > > **Issue taxonomy** maps `Missing GatewayClass` to **gateway_not_ready** and `Missing Gateway parent` to **gateway_route_invalid**; user-facing catalog copy is updated accordingly. > > **Dedupe** no longer drops every `ResolvedRefs:*` condition when any structural missing-ref exists on the route. It only hides **matching** controller echoes (e.g. backend missing → `BackendNotFound` / `PortNotFound`; ReferenceGrant → `RefNotPermitted`). A **missing parent** structural row does **not** suppress unrelated `ResolvedRefs` conditions. > > **Dynamic cache authority**: new `HasWatchedInSyncedNamespace` returns “missing” only when the relevant informer has **synced** for that namespace (including during informer scope replacement). **KEDA `Rollout` scaleTargetRefs** use the same rule so partial watches don’t emit false **missing scaleTargetRef** issues. Initial add-event suppression is renamed/clarified so it isn’t confused with sync authority. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 93ee479. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
nadaverell
added a commit
that referenced
this pull request
Aug 9, 2026
## Summary - detect Gateways that reference a missing GatewayClass after a two-minute reconciliation grace - detect HTTPRoute, GRPCRoute, TCPRoute, and TLSRoute parentRefs that target a missing Gateway - require authoritative cluster or exact-namespace informer coverage before asserting absence - preserve unrelated Gateway controller conditions while deduplicating exact structural echoes, including Envoy Gateway PortNotFound - apply the same authority check to KEDA Rollout scaleTargetRefs so partial caches cannot produce false missing-target issues ## Validation - `make build` - `make test` - `make tsc` - `go test ./internal/issues ./internal/k8s` - `go test ./...` from `pkg/k8score/` - live EKS smoke on `radar-test-nonprod`: grace suppression, both findings present, target creation recovery, and fixture cleanup - Playwright Issues-page smoke with both findings rendered and zero console errors - visual-test skipped: no UI delta ## Stack - stacked on #1391 - #1391 is stacked on #1390 Linear: RAD-346 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes live issue detection for Gateway networking and dynamic-cache “absence” semantics; incorrect authority or dedupe could hide real problems or briefly miss issues during informer sync, but behavior is heavily tested and biased toward silence when coverage is incomplete. > > **Overview** > Extends **Gateway API missing-reference detection** beyond route backend Services: after a **2-minute grace**, it flags **Gateways** with a non-existent `spec.gatewayClassName` and **routes** (`HTTPRoute`, `GRPCRoute`, `TCPRoute`, `TLSRoute`) whose `parentRefs` point at a **missing Gateway** (same- or cross-namespace). **Backend Service / port / ReferenceGrant** checks still require the Service lister; **topology** checks (class + parent) run even when Services aren’t available. > > **Issue taxonomy** maps `Missing GatewayClass` to **gateway_not_ready** and `Missing Gateway parent` to **gateway_route_invalid**; user-facing catalog copy is updated accordingly. > > **Dedupe** no longer drops every `ResolvedRefs:*` condition when any structural missing-ref exists on the route. It only hides **matching** controller echoes (e.g. backend missing → `BackendNotFound` / `PortNotFound`; ReferenceGrant → `RefNotPermitted`). A **missing parent** structural row does **not** suppress unrelated `ResolvedRefs` conditions. > > **Dynamic cache authority**: new `HasWatchedInSyncedNamespace` returns “missing” only when the relevant informer has **synced** for that namespace (including during informer scope replacement). **KEDA `Rollout` scaleTargetRefs** use the same rule so partial watches don’t emit false **missing scaleTargetRef** issues. Initial add-event suppression is renamed/clarified so it isn’t confused with sync authority. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 93ee479. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
nadaverell
force-pushed
the
fix/rad-346-onset-provenance
branch
from
August 9, 2026 13:03
a2fce69 to
e2c2e3d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
first_seenas “active at least since,” never exact onset, across API docs, MCP, and UIfirst_seen=0as 1970Fleet validation
mainand this branch across all configured clustersradar-test-prod, 0 of the first 1,000 rows carry redundant all-known coverageValidation
make testmake tscmake buildradar-test-prod(3,200 issues): API/UI healthy, zero browser console errorsfirst_seenfilter rejected with HTTP 400 and actionable guidance; guarded filter returned HTTP 200health regressed,active at least …, and the owner-workload attribution caveat in the production buildRisk and rollback
This is a broad read-path change: issue membership and diagnosis are unchanged, but timing fields are consumed by the UI, MCP agents, and CEL filters. Unknown onset is now explicit, and previously unguarded
first_seenage filters fail loudly instead of returning misleading matches. Reverting this PR restores the prior timing behavior.Follow-up to RAD-346.
Note
Medium Risk
Broad read-path change to timing fields used by the UI, MCP agents, and CEL filters; issue membership is unchanged but clients must handle unknown onset and stricter filter validation.
Overview
Issue timing is now evidence-backed end-to-end:
first_seenis set only from explicit anchors (OnsetAt, conditionlastTransitionTime, deletion time, trackers, etc.), not from resource age or compose-time guesses. Missing anchors surface asonset_unknownwithresource_created_atkept as separate context, and grouped rows can carryonset_coveragewhen members disagree on whether onset is known.Detectors and condition sources were updated to pass parsed transition times (including CAPI, Velero, Helm, gateway routes, CNPG) and to mark unknown onset when timestamps are absent or in the future.
setDetectionOnsetcentralizes duration/OnsetUnknownderivation; problem normalization no longer fabricates onset fromAgeSeconds/DurationSeconds.Aggregation behavior uses
foldIssueOnsetfor grouping and duplicate-env rollups, sorts unknown-onset issues by resource creation viaissueSortAnchor, drops symptom→structural issue_timing donation, and clears group-wide timing when onset coverage is mixed. Public timestamps are normalized to UTC before filters run.Consumers: MCP/docs describe
first_seenas “active at least since”; CEL issue filters gainonset_unknown,onset_coverage_unknown, andresource_created_at, with compile-time rejection of age filters that usefirst_seenwithout guarding unknown onset (first_seen != 0,!onset_unknown, etc.).Reviewed by Cursor Bugbot for commit 8a266b3. Bugbot is set up for automated code reviews on this repo. Configure here.