### What happened?

When continuously re-applying the same object via a controller or kubectl with SSA the resourceVersion increases every time.

### What did you expect to happen?

I expected the resourceVersion to stay the same if the client always sends the same object via SSA, especially if the  resulting object doesn't change (apart from resourceVersion & managedFields, but these are managed by the apiserver).

### How can we reproduce it (as minimally and precisely as possible)?

Apply this CRD: 

```bash
kubectl apply -f ./crd_machines.yaml
```

<details>
<summary>crd_machines.yaml</summary>

```yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: machines.cluster.x-k8s.io
spec:
  group: cluster.x-k8s.io
  names:
    kind: Machine
    listKind: MachineList
    plural: machines
    singular: machine
  scope: Namespaced
  versions:
  - name: v1beta1
    schema:
      openAPIV3Schema:
        properties:
          apiVersion:
            type: string
          kind:
            type: string
          metadata:
            type: object
          spec:
            properties:
             infrastructureRef:
               properties:
                 name:
                   type: string
                 namespace:
                   type: string
                   default: default-namespace
               type: object
               x-kubernetes-map-type: atomic
            type: object
        type: object
    served: true
    storage: true
```

</details>

Apply this CR:

```bash
kubectl apply -f ./cr_machine.yaml --server-side=true --field-manager=test-manager
```

<details>
<summary>cr_machine.yaml</summary>

```yaml
apiVersion: cluster.x-k8s.io/v1beta1
kind: Machine
metadata:
  name: machine-1
  namespace: default
spec:
  infrastructureRef:
    name: infrastructure-machine-1
```

</details>

Get state of the CR after first apply
```bash
k get machine -o yaml --show-managed-fields > /tmp/machine-1.yaml
```

Apply the CR again
```bash
kubectl apply -f ./cr_machine.yaml --server-side=true --field-manager=test-manager
```

Get state of the CR after second apply
```bash
k get machine -o yaml --show-managed-fields > /tmp/machine-2.yaml
```

Diff
```bash
diff /tmp/machine-1.yaml /tmp/machine-2.yaml
```

```bash
16c16
<       time: "2024-04-29T09:39:07Z"
---
>       time: "2024-04-29T09:39:40Z"
19c19
<     resourceVersion: "1167"
---
>     resourceVersion: "1209"
```

=> The resourceVersion and the "time" field of the managedField entry of the "test-manager" increases.




### Anything else we need to know?

The use case we have is a lot more complex than this simple scenario. The tl;dr is that we want to implement caching for our SSA calls, so that we don't have SSA calls on every reconcile of our controller if nothing actually changes. This is relatively hard to do if the resourceVersion increases after every apply.


I took a closer look at the APIserver and ~ the following happens:

1. the "incoming" SSA patch is applied over the live object from etcd
    1. this leads to a change because `infrastructureRef` has `x-kubernetes-map-type: atomic` which means the `namespace` field will be dropped
    2. Because of that change the "time" field in the managedField entry gets set to "time.Now()" [here](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/util/managedfields/internal/managedfieldsupdater.go#L76)
    3. later during admission the namespace field gets defaulted again (I also tried this with a mutating webhook, same result)

On a high-level:
* client always applies the same object
* defaulting always results in the same object
* resourceVersion and managedFields[].time continuously go up

I think there are many similar cases that would lead to this behavior. Basically whenever the admission chain mutates a field previously set via SSA.

Notes:
* This only happens if there is >1s between each apply, otherwise the managedField[].time is identical and then the resourceVersion stays the same (because we then don't write to etcd)

### Kubernetes version

<details>

```console
$  kubectl version
Client Version: v1.29.0
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.29.2
```

I also tried this with client-go v0.30 and kube-apiserver v1.30. Same result.

</details>


### OS version

<details>

Running this natively on Apple Silicon M2. But can't imagine this makes a difference. Also got the same results in Docker Desktop on Mac.

</details>

Server-side apply bumps resourceVersion when re-applying the same object
This is a GitHub Issue
repo:kubernetes
owner:kubernetes
Title : Server-side apply bumps resourceVersion when re-applying the same object
Issue date:

--- start body ---
### What happened?

When continuously re-applying the same object via a controller or kubectl with SSA the resourceVersion increases every time.

### What did you expect to happen?

I expected the resourceVersion to stay the same if the client always sends the same object via SSA, especially if the  resulting object doesn't change (apart from resourceVersion & managedFields, but these are managed by the apiserver).

### How can we reproduce it (as minimally and precisely as possible)?

Apply this CRD: 

```bash
kubectl apply -f ./crd_machines.yaml
```

<details>
<summary>crd_machines.yaml</summary>

```yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: machines.cluster.x-k8s.io
spec:
  group: cluster.x-k8s.io
  names:
    kind: Machine
    listKind: MachineList
    plural: machines
    singular: machine
  scope: Namespaced
  versions:
  - name: v1beta1
    schema:
      openAPIV3Schema:
        properties:
          apiVersion:
            type: string
          kind:
            type: string
          metadata:
            type: object
          spec:
            properties:
             infrastructureRef:
               properties:
                 name:
                   type: string
                 namespace:
                   type: string
                   default: default-namespace
               type: object
               x-kubernetes-map-type: atomic
            type: object
        type: object
    served: true
    storage: true
```

</details>

Apply this CR:

```bash
kubectl apply -f ./cr_machine.yaml --server-side=true --field-manager=test-manager
```

<details>
<summary>cr_machine.yaml</summary>

```yaml
apiVersion: cluster.x-k8s.io/v1beta1
kind: Machine
metadata:
  name: machine-1
  namespace: default
spec:
  infrastructureRef:
    name: infrastructure-machine-1
```

</details>

Get state of the CR after first apply
```bash
k get machine -o yaml --show-managed-fields > /tmp/machine-1.yaml
```

Apply the CR again
```bash
kubectl apply -f ./cr_machine.yaml --server-side=true --field-manager=test-manager
```

Get state of the CR after second apply
```bash
k get machine -o yaml --show-managed-fields > /tmp/machine-2.yaml
```

Diff
```bash
diff /tmp/machine-1.yaml /tmp/machine-2.yaml
```

```bash
16c16
<       time: "2024-04-29T09:39:07Z"
---
>       time: "2024-04-29T09:39:40Z"
19c19
<     resourceVersion: "1167"
---
>     resourceVersion: "1209"
```

=> The resourceVersion and the "time" field of the managedField entry of the "test-manager" increases.




### Anything else we need to know?

The use case we have is a lot more complex than this simple scenario. The tl;dr is that we want to implement caching for our SSA calls, so that we don't have SSA calls on every reconcile of our controller if nothing actually changes. This is relatively hard to do if the resourceVersion increases after every apply.


I took a closer look at the APIserver and ~ the following happens:

1. the "incoming" SSA patch is applied over the live object from etcd
    1. this leads to a change because `infrastructureRef` has `x-kubernetes-map-type: atomic` which means the `namespace` field will be dropped
    2. Because of that change the "time" field in the managedField entry gets set to "time.Now()" [here](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/util/managedfields/internal/managedfieldsupdater.go#L76)
    3. later during admission the namespace field gets defaulted again (I also tried this with a mutating webhook, same result)

On a high-level:
* client always applies the same object
* defaulting always results in the same object
* resourceVersion and managedFields[].time continuously go up

I think there are many similar cases that would lead to this behavior. Basically whenever the admission chain mutates a field previously set via SSA.

Notes:
* This only happens if there is >1s between each apply, otherwise the managedField[].time is identical and then the resourceVersion stays the same (because we then don't write to etcd)

### Kubernetes version

<details>

```console
$  kubectl version
Client Version: v1.29.0
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.29.2
```

I also tried this with client-go v0.30 and kube-apiserver v1.30. Same result.

</details>


### OS version

<details>

Running this natively on Apple Silicon M2. But can't imagine this makes a difference. Also got the same results in Docker Desktop on Mac.

</details>

--- end body ---
