Repository navigation
Header chip and GitOps write guard read the manager answer - #2325
Conversation
Only an owner Radar couldn't read or decide, or a looping or overlong chain, leaves a manager above it unread and warrants the conservative warning; a gone or replaced owner ends the chain with an answer.
A claim its manager's list confirms read as a second line about the same manager; it now joins the list's line. Claims copied from another object, as the tracking annotation a ReplicaSet inherits from its Deployment, add nothing and are left out; a claim that disagrees is said first.
PR Summary by QodoUse server manager answers for GitOps chips and write warnings
AI Description
Diagram
High-Level Assessment
Files changed (15)
|
Code Review by Qodo
1.
|
…ount one Application once A Pod managed through its Deployment now says via Deployment on the chip, not only in the tooltip. An opt-out on the target's own annotations, as Flux's reconcile: disabled, holds for an unconfirmed claim too. A tracking ID and an instance label naming one Application are one candidate, not two.
A ReplicaSet carries its Deployment's Helm release annotations; with a plain Helm Deployment they made each ReplicaSet edit warn as if a GitOps tool might revert it, rather than note that it is generated from the Deployment.
…ownership/manager-chip-guard
…t an unconfirmed answer - A list alone (listed) can name an object its manager doesn't sync: a copy carrying another object's tracking ID, or a CRD a HelmRelease skips. It now gives may-revert, and the chip says Listed by. - The write-evidence response says when the server couldn't answer what manages the live object (managerUnavailable); the client owner hint and the cached answer are then not used. A failed evidence request leaves a cached answer that names a manager unconfirmed. - The dialog checks every cached answer against the live object, including none and unknown. - A native Helm release's annotations beside an Argo CD or Kustomization lead mean an adopted install; that manager's exemption no longer waives the release's next upgrade or rollback. - Generated-from-parent notes say what the evidence says of the parent. - A chip with several candidates opens a menu naming each and what names it; a chip without a link is focusable, so its tooltip is reachable by keyboard. The remote reason says Radar can't confirm the destination.
…ownership/manager-chip-guard
…ownership/manager-chip-guard
…idate - A listed answer's reason no longer carries a will-recreate or will-overwrite promise under a may-revert verdict: it says the list names the object and a sync may apply it. - Generated-from-parent notes for a parent the managers disagree on say which manager its metadata names and which lists it. - The chip's menu names every candidate; one whose label names no namespace is shown without a link.
…nes Radar found The app passed the chip's open handler only when it could fetch the lead's object, so a disagreement, which has no lead, opened nothing. With a manager answer the handler is passed; the chip links a manager only when its list names the object or Radar read the manager its metadata names, never a missing, withheld or unresolved one.
…ownership/manager-chip-guard
…ownership/manager-chip-guard
…values from newer Radars A Job created from a CronJob (scheduled or by hand) runs once: deleting it no longer says its controller recreates it. A manager state, claim check or source this UI doesn't know is shown generically and read as an unconfirmed claim, instead of throwing in the tooltip or linking. A manager one claim read is linked even when another claim left it unresolved.
…ownership/manager-chip-guard
…ownership/manager-chip-guard
…ownership/manager-chip-guard
…ownership/manager-chip-guard
A claimed answer whose only candidate had no lead (an unfamiliar state from a newer Radar) or was a manager kind this UI doesn't map fell through to no warning. It now asks for an acknowledgement like any unconfirmed claim; a native Helm lead keeps its own rules.
The listed rewrite replaced the whole reason, dropping what the field evidence said (an ignore rule that only affects comparison, a suspended manager) and naming the Application twice. It now says once that Radar can't confirm a sync applies the object, then gives the original reason under 'If one does:'.
…ownership/manager-chip-guard
- Tracked by says up front that Radar hasn't confirmed the manager the metadata names; claims passed on the way show without via too. - The manager's sync status shows on the chip only for agree, where it is this resource's manager; beside a list alone it read as the resource's own state. - An informational note on a list-only answer says Listed by, as the chip does, not Managed by. - The list-only warning leads with what Radar can't confirm, then the field evidence under 'If it does:'. - A CronJob's Job delete says the CronJob can still create new Jobs.
…ownership/manager-chip-guard
Bugbot needs on-demand usage enabledBugbot 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. |
When the answer came from an ancestor above the CronJob, the note said that ancestor could create new Jobs on its schedule.
This is #2325's change, reopened against `main`. #2325 merged into its stacked base branch after #2320 had already merged, so none of it reached `main`. Same code as #2325's final head, with current `main` merged in, plus shorter docs: `docs/ownership.md` holds the manager-answer rules (states as a table), the `docs/mcp.md` section keeps what an agent needs, and the `docs/gitops.md` write-warning rules are one table of answer by operation. ## Problem The header chip and the GitOps write guard decide "which manager owns this" in the browser: - the chip uses the first tracking label it finds, inherits a parent's manager one hop up, and guesses an Argo CD Application's namespace by name; - the write guard trusts whatever owner the browser sends and never checks the managers' status lists. With no owner it says nothing. So the chip and the warning could name a manager whose list doesn't include the object, or miss a second manager whose list does. ## Change **Chip.** When the server sends `relationships.ownership.manager` (#2319), the chip reads it: no browser inheritance, no guess by name. With an older Radar backend the chip behaves exactly as before; Radar Hub runs the newest UI against older Radars. | state | chip | tooltip | |---|---|---| | agree | Managed by X | the list naming it, and that its tracking metadata agrees | | listed | Listed by X | the list naming it; a list alone can name an object its manager doesn't sync (a copy carrying another object's tracking ID, a CRD a HelmRelease skips) | | via an ancestor | same wording, plus "via <Kind>" | "Through Deployment …", plus the object's own weak claims | | claimed | Tracked by X | why the claim couldn't be confirmed: omitted, unreadable, remote, missing, withheld, … | | disagree | Tracked by A, with a warning | A's list doesn't name it; B's does | | shared | Listed by A and B | no single manager's sync status shown | | unknown / none | no chip | — | With several candidates (disagree, shared, several claims) the chip opens a menu naming each and what names it (its status, its metadata or both); with one it opens that manager. A chip without a link is focusable, so keyboard users reach its tooltip. Related Resources' Managed By group is hidden only when the chip says exactly what it would. **Write guard.** - **The server decides.** `POST /api/gitops/write-evidence` computes the manager answer itself, as the caller, reading the live target's metadata, and returns it as `manager`. Its lead decides which manager's policy applies. The client's owner is only a hint when the server has no ownership answer for the kind. When the server computed one and couldn't finish (the object was replaced since the cache saw it, the cache isn't ready), `managerUnavailable` says why, and neither the hint nor the cached answer is used: the dialog warns and asks for an acknowledgement. - **Every cached answer is checked live,** including `none` and `unknown`: an object adopted since the cache saw it has a manager the cache doesn't. One request per guarded dialog. A failed request leaves a cached answer that names a manager unconfirmed (acknowledgement); a cached `none` stays quiet. - **The classifier composes.** The existing operation rules are unchanged: status writes say nothing, creating a child is informational, an operator-owned delete is informational. On top of them: - **disagree, shared, or several claims:** field writes get "may revert", naming every candidate, and no single candidate's ignore rules or sync policy exempt the change; - **an unconfirmed claim** (omitted, unreadable, remote, missing, withheld): can't prove "will revert" or waive the acknowledgement; - **"will revert" needs the list and the object's metadata to agree** (`agree`). A list alone (`listed`) gives "may revert", saying Radar can't confirm a sync applies the object, then the field evidence under "If one does:"; - **a CronJob's Job** (scheduled, or made with `kubectl create job --from`) runs once: deleting it doesn't say its controller recreates it; - **values from a newer Radar** (a state, check, source or chain end this UI doesn't know) render generically and read as unconfirmed, so they never prove a revert, waive a warning or link a manager; - **an adopted Helm install:** a native Helm release's annotations beside an Argo CD Application or Flux Kustomization keep "may revert" even when that manager ignores the field, since the release's next upgrade or rollback can still overwrite it; - **via an ancestor, with no claim of the object's own:** informational ("generated from <parent>, which X manages", or "which X lists", or "whose metadata names X", as the evidence allows), no acknowledgement; - **via, with the object's own claim:** keeps "may revert"; - **a chain Radar couldn't read** (owner withheld, unknown or unresolvable, a loop, too long): keeps the conservative "couldn't tell" warning. An owner that is gone or replaced ends the chain with an answer and adds no warning; - **no `manager` in the evidence** (older Radar): verdicts as before. ## Verification - **Tests.** Classifier tests cover each rule above, including: - an ignore rule on one of two managers still warning; - a status write on a shared object staying silent; - gone and replaced owners not warning. Chip tests cover every state's wording, plural names, and the group-hiding rule. Hook tests check the evidence query fires for ambiguous and inherited answers and that the server's answer wins over the client's. Server tests check `manager` in the response and that the server's lead overrides a conflicting client owner. A live-overlay test covers live metadata, a replaced UID, a cache switch and restricted access. - **Checks.** `make tsc` is clean. Frontend: 5,290+ tests across the UI package, 64 hook tests in the app. Go: `pkg/...`, `internal/k8s`, `internal/server`, `internal/mcp`. - **Live on a test cluster:** - a relabelled Flux Pod reads "Tracked by flux-system/wg-ks" with a warning; the tooltip says wg-ks's status doesn't list it, wg-ks-susp's does, through its Deployment; - a Pod of a Deployment two Applications list reads "Listed by …-a and …-b"; - an ordinary Argo CD Deployment reads "Managed by … · Synced", and its Managed By group is hidden; - the disagreeing Deployment's Set image dialog warns that both Kustomizations may overwrite the fields and requires the acknowledgement; - the write-evidence endpoint answers a Pod through its Deployment's Application even when the client sends a different owner.
Stacked on #2320, which is on #2319.
Problem
The header chip and the GitOps write guard decide "which manager owns this" in the browser:
So the chip and the warning could name a manager whose list doesn't include the object, or miss a second manager whose list does.
Change
Chip. When the server sends
relationships.ownership.manager(#2319), the chip reads it: no browser inheritance, no guess by name. With an older Radar backend the chip behaves exactly as before; Radar Hub runs the newest UI against older Radars.With several candidates (disagree, shared, several claims) the chip opens a menu naming each and what names it (its status, its metadata or both); with one it opens that manager. A chip without a link is focusable, so keyboard users reach its tooltip.
Related Resources' Managed By group is hidden only when the chip says exactly what it would.
Write guard.
POST /api/gitops/write-evidencecomputes the manager answer itself, as the caller, reading the live target's metadata, and returns it asmanager. Its lead decides which manager's policy applies. The client's owner is only a hint when the server has no ownership answer for the kind. When the server computed one and couldn't finish (the object was replaced since the cache saw it, the cache isn't ready),managerUnavailablesays why, and neither the hint nor the cached answer is used: the dialog warns and asks for an acknowledgement.noneandunknown: an object adopted since the cache saw it has a manager the cache doesn't. One request per guarded dialog. A failed request leaves a cached answer that names a manager unconfirmed (acknowledgement); a cachednonestays quiet.agree). A list alone (listed) gives "may revert", saying Radar can't confirm a sync applies the object, then the field evidence under "If one does:";kubectl create job --from) runs once: deleting it doesn't say its controller recreates it;managerin the evidence (older Radar): verdicts as before.Verification
Tests. Classifier tests cover each rule above, including:
Chip tests cover every state's wording, plural names, and the group-hiding rule. Hook tests check the evidence query fires for ambiguous and inherited answers and that the server's answer wins over the client's. Server tests check
managerin the response and that the server's lead overrides a conflicting client owner. A live-overlay test covers live metadata, a replaced UID, a cache switch and restricted access.Checks.
make tscis clean. Frontend: 5,290+ tests across the UI package, 64 hook tests in the app. Go:pkg/...,internal/k8s,internal/server,internal/mcp.Live on a test cluster: