Kubernetes ssa field ownership triage
Skill mouadja02/skills/skills/devops/kubernetes-ssa-field-ownership-triage
A curated collection of agent skills for your AI agents - engineering craft, prompt engineering, design, growth marketing, ...
npx -y skills add mouadja02/skills --skill kubernetes-ssa-field-ownership-triageAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when Kubernetes Server-Side Apply reports field-manager conflicts, controllers overwrite fields, or force-conflicts risks pruning/defaulting side effects; diagnose ownership read-only before choosing relinquish, partition, or explicit transfer.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
10.7 KB, ~2.2k tokens by cl100k_base, as published. Nobody here has run it
Kubernetes SSA Field Ownership Triage
When to Use
kubectl apply --server-sideor another SSA client reports a field conflict.- Argo CD, Terraform, Helm, an operator, or a webhook appears to fight over fields.
- A forced apply removed injected/defaulted values or caused recurring drift.
- A team must decide whether to relinquish, partition, or transfer ownership.
Do not use this for client-side three-way-merge errors, immutable-field errors, ordinary Helm template design, or non-Kubernetes state conflicts. Do not treat managedFields as a historical audit log.
Prerequisites
- Read access to the resource and its CRD/schema when applicable.
kubectlmatched reasonably closely to the API server.- The exact apply client, field-manager name, intended manifest, and conflict text.
- Python 3.9+ only if using the optional offline analyzer.
- A backup and explicit human approval before any live ownership transfer.
Safety Rules
- Start read-only. Save redacted evidence outside the repository.
- Never recommend
--force-conflictsmerely to make reconciliation green. - Do not edit
metadata.managedFieldsdirectly; it is API-server-managed state. - Test with server dry-run, but remember admission/defaulting still participates and dry-run support can vary by webhook.
- Identify the controller responsible for each manager before changing manifests or manager names.
- A live force operation is an ownership transfer and may prune fields omitted by the new owner. Require a reviewed payload, backup, rollback, and named approver.
Quick Reference
# Preserve the exact live object for offline inspection; redact sensitive data.
kubectl get deployment api -n prod -o json > /tmp/api-live.json
# Inventory manager/path claims without contacting the cluster.
python3 scripts/ssa_ownership.py inventory /tmp/api-live.json
# Parse an apply error captured as plain text.
python3 scripts/ssa_ownership.py conflicts /tmp/apply-error.txt
# Reproduce admission and ownership checks without persisting a change.
kubectl apply --server-side --dry-run=server \
--field-manager=my-deployer -f intended.yaml -o yaml
Procedure
1. Freeze the evidence
Record:
- cluster and Kubernetes version;
- resource GVK, namespace, name, and
resourceVersion; - apply client/version and exact
--field-managervalue; - intended object after rendering, with secrets redacted;
- full conflict message;
- active reconcilers, mutating webhooks, and GitOps/Terraform ownership.
Fetch the live object once. Avoid loops that repeatedly apply while diagnosing: even no-op SSA requests can change managed-field metadata in some Kubernetes versions.
Completion: one timestamped live object, one intended object, and one exact error are available for comparison.
2. Map managers to owned paths
Inspect .metadata.managedFields[] by manager, operation, API version, subresource, and fieldsV1. Use the helper for a readable inventory, then verify important paths against the raw object.
python3 scripts/ssa_ownership.py inventory /tmp/api-live.json --pretty
Interpret ownership as a current field set, not proof of who last changed a value. The same manager string may be reused by unrelated clients; operation and workflow identity matter. For CRDs, inspect structural schema and list semantics (atomic, set, or map) because one apparent list item can be owned atomically or by keyed element.
Completion: every conflicting path has a current owner, operation, API version, and responsible controller/client—or is explicitly marked unknown.
3. Classify the conflict
Use the first matching class:
| Class | Evidence | Preferred direction |
|---|---|---|
| Accidental duplicate manager | Different clients reuse one manager name | Give each workflow a stable unique manager; retest |
| Shared desired field | Two reconcilers intentionally set the same scalar/atomic collection | Establish one source of truth; remove it from the other payload |
| Defaulted field | API defaulting adds a value that another client sends explicitly | Omit the default where safe or make one manager authoritative |
| Webhook-injected field | Mutating webhook owns/adds data after admission | Exclude it from deployer payload; test omission and pruning |
| Controller-owned status/subresource | Conflict concerns status or scale ownership | Use the proper subresource/client contract |
| List semantics mismatch | Ownership is at whole-list rather than keyed-item scope | Fix CRD schema or partition ownership; do not force blindly |
| Stale manager | Former controller still owns fields and no longer runs | Prove decommissioning, then plan explicit transfer |
| Version/schema drift | Manager entries or paths differ across served API versions | Compare conversion and schema behavior before transfer |
Do not infer “stale” from an old managed-field timestamp alone. Prove that no active controller uses that manager.
4. Reproduce without mutation
Run the exact rendered payload with the exact manager using server dry-run. Keep force disabled first.
kubectl apply --server-side --dry-run=server \
--field-manager="$MANAGER" -f intended.yaml -o json > /tmp/dry-run.json
Test one hypothesis at a time:
- original payload and manager;
- payload with disputed fields omitted;
- stable unique manager, only when manager collision is suspected;
- disposable namespace/cluster fixture for webhook, defaulting, or list-semantics behavior.
Compare values and field ownership, including fields absent from the intended payload. If a webhook does not support dry-run, stop and use a disposable environment rather than testing in production.
Completion: the failure boundary is reproducible, and one non-mutating variant removes the conflict without losing required fields—or the uncertainty is documented.
5. Choose the least risky ownership transition
Decision order:
- Relinquish: remove fields the client does not intend to own. Confirm the live value remains correct after a disposable apply.
- Partition: split manifests/controllers so each owns disjoint schema fields or keyed list items.
- Coordinate: pause or reconfigure one reconciler and document a single source of truth.
- Transfer: only if the old owner is intentionally displaced. Review the complete payload and omitted-field behavior, then obtain approval for force.
A transfer plan must name the old and new manager, exact paths, pause order, backup, canary object, rollback command, and post-apply ownership assertions. Never force an entire rendered object when only a small, deliberately reviewed field set requires transfer.
6. Verify recovery
After an approved canary change:
kubectl get <kind> <name> -n <namespace> -o json > /tmp/after.json
python3 scripts/ssa_ownership.py inventory /tmp/after.json --pretty
kubectl diff --server-side --field-manager="$MANAGER" -f intended.yaml
Require all of these:
- the intended manager owns only the approved paths;
- the displaced manager no longer reclaims them after at least two reconciliation intervals;
- webhook/defaulted fields remain present;
- no unrelated path was pruned or changed;
- a repeated dry-run/apply is conflict-free and convergent;
- rollback remains possible from the saved object or source-of-truth manifest.
Failure Recovery
- Dry-run changes behavior: stop; verify webhook
sideEffectsand dry-run support, then reproduce in a disposable cluster. - Manager cannot be identified: do not force. Correlate controller deployment, audit logs, and manager naming configuration.
- Force pruned fields: pause the new reconciler, restore the reviewed prior values through the legitimate owner, and verify admission/controller convergence.
- Conflict returns: an active reconciler still claims the field. Revert the transfer and establish a single owner rather than repeating force.
- CRD list ownership is unexpectedly atomic: restore the previous CRD/controller version if safe and redesign schema/list ownership before retrying.
Objective Verification Checklist
- Exact conflict text and rendered payload preserved.
- Conflicting paths mapped to managers from raw
managedFields. - Defaulting, webhook mutation, subresources, and list semantics considered.
- Failure reproduced with server dry-run or a disposable fixture.
- Recovery transition proven without unrelated pruning.
- Live force, if any, has explicit approval, backup, canary, and rollback.
- Repeated reconciliation converges without ownership churn.
Evaluation Prompts
- Normal: “Argo CD SSA says
conflict with kubectlon.spec.replicas. Diagnose it without changing the Deployment.” - Difficult edge: “A forced apply to a CRD removed a webhook-injected annotation and two entries from a map-like list. Determine whether defaulting, webhook ownership, or CRD list semantics caused it and design a disposable recovery test.”
- Should not activate: “Create a Helm chart with a Deployment, Service, probes, and secure defaults.”
Expected observable behavior: prompts 1–2 map managers and paths, classify ownership, reproduce without mutation, and gate force behind approval; prompt 3 routes to a Helm/chart workflow instead.
Sourced Facts and Recommendations
Sourced facts: Kubernetes documents SSA field tracking in managedFields, conflict behavior, field-manager identity, merge markers/list topology, and force-conflict transfer. The cited issues demonstrate current cross-project failure modes involving no-op metadata updates, forced pruning of injected annotations, operator ownership, and stale provider payload fields.
Recommendations: the classification table, evidence packet, decision order, canary rules, and approval gates are original operational guidance synthesized for safe triage.
Sources
- Kubernetes Server-Side Apply documentation (accessed 2026-07-25): https://kubernetes.io/docs/reference/using-api/server-side-apply/
- Kubernetes no-op SSA managed-fields issue: https://github.com/kubernetes/kubernetes/issues/131175
- Argo CD forced-apply pruning issue: https://github.com/argoproj/argo-cd/issues/28721
- MariaDB Operator ownership-conflict issue: https://github.com/mariadb-operator/mariadb-operator/issues/1738
- Terraform Kubernetes provider stale-annotation issue: https://github.com/hashicorp/terraform-provider-kubernetes/issues/2894
No source prose or code is redistributed. This skill and helper are original MIT-licensed work.