# Deep Review: 20260315-180016-pr-188

| | |
|---|---|
| **Date** | 2026-03-15 18:00 |
| **PR** | [#188](https://github.com/rancher-sandbox/rancher-desktop-daemon/pull/188) — mock: namespaces: ensure we have all namespaces |
| **Reviewers** | Claude Opus 4.6, Codex GPT 5.4, Gemini 3.1 Pro |
| **Verdict** | **Merge with fixes** — self-referential ownerReference on rancher-desktop namespace breaks GC and causes reconciliation oscillation |
| **Wall-clock time** | 19 min 7 s |

---

## Consolidated Review

### Executive Summary

Three commits make the container `pid` field optional, move mock resources from the `default` to the `rancher-desktop` Kubernetes namespace, and create `ContainerNamespace` resources for all volume namespaces. The new `kubeNamespaceReconciler` has a self-referential ownership bug: it applies `rancher-desktop`'s ownerReference pointing to itself instead of `rdd-mocks`, breaking garbage collection and causing reconciliation oscillation. This should merge with fixes.

**Structure:** 3 commits — make pid optional in container CRD, move mock resources to `rancher-desktop` namespace, ensure ContainerNamespace resources exist for volume namespaces.

### Important Issues

1. **`rancher-desktop` namespace overwrites its own ownerReference** — `pkg/controllers/mock/kube_namespace_reconciler.go:27-84` [Claude Opus 4.6, Codex GPT 5.4, Gemini 3.1 Pro]

```go
// SetupWithManager: both For and Watches target corev1.Namespace
For(&corev1.Namespace{}).
    Watches(&corev1.Namespace{},
        handler.EnqueueRequestForOwner(..., &corev1.Namespace{}, ...)).
    WithEventFilter(predicate.NewPredicateFuncs(func(object client.Object) bool {
        switch object.GetName() {
        case mockNamespaceName, apiNamespace:
            return true
        }
        // ...
    }))
```

The `For` handler enqueues the namespace name directly, while `Watches` with `EnqueueRequestForOwner` enqueues the owner. The predicate at line 75 admits both `rdd-mocks` and `rancher-desktop`. When `rancher-desktop` triggers an event, `For` enqueues `{Name: "rancher-desktop"}`. The reconciler at line 31 fetches `rancher-desktop`, builds an ownerReference from it (lines 41-47), and applies it back to `rancher-desktop` (lines 49-55) — a self-referential ownership.

This overwrites the correct `rdd-mocks` ownerReference set by the `{Name: "rdd-mocks"}` reconcile. The resulting oscillation flips ownership between `rdd-mocks` and `rancher-desktop` on each event. When `rancher-desktop` owns itself, deleting `rdd-mocks` orphans it. Codex confirmed this against a live control plane: `ownerReferences.name` alternated between `rancher-desktop` and `rdd-mocks` depending on event order.

All lines confirmed as commit 7ce6b31 via `git blame`.

Gemini rated this Critical; Claude and Codex rated it Important. Assessment: **Important.** The bug will manifest reliably, but its blast radius is limited to mock controller test infrastructure in an embedded single-user kube-apiserver. No production data loss or security impact.

Fix: Early-return in `Reconcile` for requests other than the intended trigger namespace:

```go
func (r *kubeNamespaceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    if req.Name != mockNamespaceName {
        return ctrl.Result{}, nil
    }
    // ... rest of reconcile
}
```

The predicate must still admit `apiNamespace` so the `Watches` handler can detect changes to the owned namespace and enqueue `rdd-mocks`. The guard in `Reconcile` filters out spurious `For`-originated requests.

### Suggestions

1. **Missing `IsNotFound` handling causes retry churn on namespace deletion** — `pkg/controllers/mock/kube_namespace_reconciler.go:31-34` [Gemini 3.1 Pro]

```go
var rddNamespace corev1.Namespace
if err := r.Client.Get(ctx, req.NamespacedName, &rddNamespace); err != nil {
    log.Error(err, "Failed to get namespace", "namespace", req.NamespacedName)
    return ctrl.Result{}, err
}
```

If the watched namespace is deleted, `Get` returns `IsNotFound` and the returned error causes controller-runtime to requeue indefinitely with exponential backoff. This produces log noise during cleanup.

The same pattern exists in all other mock reconcilers (`container_reconciler.go:54`, `container_namespace_reconciler.go:48`, etc.), so this is a pre-existing gap carried forward into new code — not specific to this PR. The practical impact is low: exponential backoff limits CPU waste, and the namespace is deleted only during controller shutdown.

Fix: Handle `IsNotFound` explicitly:

```go
if err := r.Client.Get(ctx, req.NamespacedName, &rddNamespace); err != nil {
    if apierrors.IsNotFound(err) {
        return ctrl.Result{}, nil
    }
    log.Error(err, "Failed to get namespace", "namespace", req.NamespacedName)
    return ctrl.Result{}, err
}
```

2. **`getVolumeName` always returns a constant namespace** — `pkg/controllers/mock/volume_reconciler.go:42-44` [Claude Opus 4.6]

```go
func getVolumeName(volume mobyvolume.Volume) (namespace, name string) {
    return containerNamespace, volume.Name
}
```

The function ignores its argument for the namespace component — it always returns `"buildkit"`. The `containerNamespaceReconciler` iterates volumes via `getVolumeName` to collect namespaces (line 59-61), but the result is always the same value already seeded at line 58. The indirection is harmless but the name implies it extracts namespace from the volume data. A brief comment would prevent confusion.

Fix: Add a comment noting this is a placeholder for future namespace-per-volume logic.

---

### Design Observations

1. **`For` + `Watches` on the same type creates a footgun** (in-scope) [Claude Opus 4.6, Codex GPT 5.4]

The `kubeNamespaceReconciler` is the only mock reconciler where `For` and `Watches` target the same resource type (`corev1.Namespace`). Every other reconciler watches Namespace as the trigger and a distinct CRD type as the managed resource, avoiding cross-contamination between handlers. Using per-source predicates (`For(..., builder.WithPredicates(...))`) instead of a global `WithEventFilter` would eliminate the class of bugs where events from the managed object are misrouted through the `For` handler.

2. **A dedicated reconciler for a single static namespace adds complexity** (in-scope) [Codex GPT 5.4]

There is exactly one Kubernetes namespace to ensure: `rancher-desktop`. The existing `createNamespace` function in `mock_controller.go:119` already ensures `rdd-mocks` at startup. Ensuring `rancher-desktop` from the same `rdd-mocks`-driven reconcile path — or even from `createNamespace` itself — would remove the `Namespace -> Namespace` watch cycle entirely and eliminate the class of self-referential ownership bugs.

---

### Testing Assessment

Coverage gaps, ranked by risk:

1. **No test for `rancher-desktop` namespace ownership.** The BATS tests verify resources exist in `rancher-desktop`, but never assert that the namespace's ownerReference points to `rdd-mocks`. A direct assertion on ownership would catch the regression in finding #1.
2. **No test for deletion cascade.** No test deletes `rdd-mocks` and verifies that `rancher-desktop` and its mock resources are garbage-collected. This is the path that exposes the ownership instability.
3. **No test for ContainerNamespace resources.** The `containerNamespaceReconciler` creates `ContainerNamespace` objects (e.g., `buildkit` in `rancher-desktop`), but no test verifies their existence.
4. **No test for the `pid` optional change.** The CRD change is mechanical and low-risk, but a test creating a Container without a `pid` value would confirm the CRD accepts it.

---

### Documentation Assessment

No blocking documentation issues. The constants `apiNamespace` and `containerNamespace` in `mock_controller.go:24-28` are well-commented. If there is user-facing API documentation for `Container.status.pid`, it should be updated to reflect the new optional semantics from commit 513f44d.

---

## Agent Performance Retro

### Claude Opus 4.6

- **Unique contributions:** Identified the `getVolumeName` constant-return issue. Provided the most detailed mechanical explanation of the reconciliation oscillation, tracing through both `For` and `Watches` handler behavior.
- **Accuracy:** All findings confirmed. No false positives.
- **Depth:** Traced the predicate interaction between `For` and `Watches` handlers. Compared against other mock reconciler predicates to show this is the only one admitting `apiNamespace`.
- **Signal-to-noise:** High signal. Two actionable findings plus two design observations.

### Codex GPT 5.4

- **Unique contributions:** Verified the bug against a live control plane, confirming the ownerReference oscillation with actual `kubectl` output. Proposed the simplest architectural fix (fold namespace creation into the existing path).
- **Accuracy:** All findings confirmed. No false positives.
- **Depth:** Live verification is strong evidence. Design observation about the self-referential watch graph is well-reasoned.
- **Signal-to-noise:** Highest signal-to-noise — focused on the one real bug with live proof, plus one actionable design observation.

### Gemini 3.1 Pro

- **Unique contributions:** Identified the `IsNotFound` error-handling gap and traced it across all mock reconcilers.
- **Accuracy:** Rated the ownership bug as Critical, which overstates the practical impact in an embedded single-user context. Otherwise accurate.
- **Depth:** Traced the `IsNotFound` pattern into sibling reconcilers. Did not verify the ownership bug live or trace the `For`/`Watches` handler mechanics as deeply.
- **Signal-to-noise:** Good. One inflated severity, but the `IsNotFound` finding was a genuine unique contribution.

### Summary Table

*Agents run concurrently and compete for system resources; durations are approximate.*

| Metric | Claude Opus 4.6 | Codex GPT 5.4 | Gemini 3.1 Pro |
|---|---|---|---|
| Duration (s) | 384 | 349 | 284 |
| Critical | 0 | 0 | 1* |
| Important | 1 | 1 | 1 |
| Suggestion | 1 | 0 | 0 |
| Design observations | 2 | 1 | 1 |
| False positives | 0 | 0 | 0 |
| Unique insights | 1 | 1 | 1 |

\* Reclassified as Important in consolidation (mock controller in embedded single-user context).

**Overall:** All three agents converged on the same core bug, providing high confidence in the finding. Codex provided the strongest evidence (live verification) and the most actionable design suggestion. Claude offered the deepest mechanical explanation of the controller-runtime interaction. Gemini contributed the only finding beyond the core bug.

---

## Skill Improvement Recommendations

- **Prompt specificity for mock/test controllers:** Agents should be told whether the code under review is production infrastructure or test/development tooling. This context affects severity calibration — Gemini rated the ownership bug Critical partly because the prompt didn't emphasize that mock controllers serve only test data generation.
- **Live verification instruction:** Codex's live verification was the strongest evidence in this review. The prompt could suggest running the code against a local control plane when feasible.
- **All agents missed the same gap:** None flagged that the `kubeNamespaceReconciler` could be eliminated entirely by extending `createNamespace` in `mock_controller.go` to create both namespaces at startup, avoiding the watch-cycle problem. Codex came closest but framed it as a design observation rather than a concrete alternative.
- **Pre-existing pattern detection:** The prompt asks agents not to flag pre-existing issues unrelated to the change, but Gemini's `IsNotFound` finding is a pre-existing pattern copied into new code. The prompt should clarify: pre-existing patterns replicated in new code are fair game as gaps.

---

## Appendix: Original Reviews

### Claude Opus 4.6

## Executive Summary

This PR moves mock controller resources from the `default` Kubernetes namespace to a dedicated `rancher-desktop` namespace, makes the container `pid` field optional, and adds infrastructure to create ContainerNamespace resources for all volume namespaces. The `rancher-desktop` namespace is created by a new `kubeNamespaceReconciler`.

The new `kubeNamespaceReconciler` has a controller setup bug that causes an infinite reconciliation oscillation. This needs fixing before merge; the remaining changes are clean.

**Structure:** 3 commits — make pid optional in the container CRD, move mock resources into `rancher-desktop` namespace, ensure all volume-derived container namespaces exist.

---

### Critical Issues

None.

### Important Issues

1. **`kubeNamespaceReconciler` oscillates between self-referential and correct ownerRef** — `kube_namespace_reconciler.go:63-85` (important, regression)

```go
return ctrl.NewControllerManagedBy(mgr).
    For(&corev1.Namespace{}).
    Named("mock-kube-namespace-reconciler").
    Watches(
        &corev1.Namespace{},
        handler.EnqueueRequestForOwner(
            mgr.GetScheme(),
            mgr.GetRESTMapper(),
            &corev1.Namespace{},
            handler.OnlyControllerOwner(),
        )).
    WithEventFilter(predicate.NewPredicateFuncs(func(object client.Object) bool {
        if _, ok := object.(*corev1.Namespace); ok {
            switch object.GetName() {
            case mockNamespaceName, apiNamespace:
                return true
            }
        }
        return false
    })).
    Complete(r)
```

Both `For` and `Watches` watch `corev1.Namespace`. The predicate at line 78 allows both `mockNamespaceName` and `apiNamespace` through, and `WithEventFilter` applies to all sources. When the `rancher-desktop` namespace is created:

- The `For` handler enqueues `{Name: "rancher-desktop"}`.
- The reconciler at line 31 fetches the `rancher-desktop` namespace, then at lines 41-47 builds an ownerReference pointing to it, and at lines 49-55 applies `rancher-desktop` owned by itself.

This self-referential apply changes the ownerReference (overwriting the correct `rdd-mocks` owner set by the `{Name: "rdd-mocks"}` reconcile). The change triggers a new Namespace update event, which enqueues both keys again. The `{Name: "rdd-mocks"}` reconcile restores the correct owner, triggering another update. The cycle repeats indefinitely.

Every other mock reconciler's predicate allows only `mockNamespaceName` for Namespace events. This reconciler is the only one that also allows `apiNamespace`, and the only one where `For` and `Watches` target the same type.

Git blame confirms all lines are from commit 7ce6b31 (this PR).

**Fix:** Guard the reconcile function to reject requests for namespaces other than `mockNamespaceName`:

```go
func (r *kubeNamespaceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    if req.Name != mockNamespaceName {
        return ctrl.Result{}, nil
    }
    // ... rest of reconcile
}
```

The predicate must still allow `apiNamespace` so the `Watches` handler can detect changes to the owned namespace and enqueue `rdd-mocks`. The guard in Reconcile is the right place to filter out the spurious `For`-originated requests.

---

### Suggestions

2. **`getVolumeName` always returns a constant namespace** — `volume_reconciler.go:42-44` (suggestion, regression)

```go
func getVolumeName(volume mobyvolume.Volume) (namespace, name string) {
    return containerNamespace, volume.Name
}
```

This function exists as preparation for volumes that live in different container namespaces, but it ignores its argument for the namespace component. The `containerNamespaceReconciler` at lines 59-61 calls it to collect unique namespaces, which always yields `{"buildkit"}` — the same value already seeded at line 58.

The indirection is harmless, but the function name suggests it extracts the volume's namespace from the data. A comment explaining it as a placeholder for future namespace-per-volume logic would prevent confusion.

**Fix:** Add a brief comment:

```go
// getVolumeName maps a Docker volume to its container namespace and name.
// Currently all volumes belong to the default container namespace; this
// function exists as the extension point for namespace-per-volume logic.
func getVolumeName(volume mobyvolume.Volume) (namespace, name string) {
    return containerNamespace, volume.Name
}
```

---

### Design Observations

**Splitting namespace creation into its own reconciler is sound** (in-scope)

The `kubeNamespaceReconciler` creates the `rancher-desktop` Kubernetes namespace as a prerequisite for all other mock resources. This establishes a clear dependency chain: `rdd-mocks` (trigger) -> `rancher-desktop` (API namespace) -> resources. Other reconcilers will fail and requeue until the namespace exists, which is standard controller behavior. The separation keeps each reconciler focused on a single concern.

**`For` + `Watches` on the same type requires care** (future)

The `kubeNamespaceReconciler` is the first mock reconciler that watches and manages the same resource type (`corev1.Namespace`) for both the trigger and the managed object. The other reconcilers avoid this because their managed types (Container, Image, Volume, ContainerNamespace) differ from the trigger type (Namespace). If future controllers need this pattern, consider using per-source predicates (`For(..., builder.WithPredicates(...))`) instead of a global `WithEventFilter`, which eliminates the cross-contamination between `For` and `Watches` handlers.

---

### Testing Assessment

The BATS tests verify that containers, images, and volumes appear in the `rancher-desktop` namespace — the core behavioral change. Coverage gaps, ranked by risk:

1. **No test for the `rancher-desktop` namespace itself.** The tests wait for `rdd-mocks` and then query resources in `rancher-desktop`, but never verify that the `rancher-desktop` namespace exists, is owned by `rdd-mocks`, or gets garbage-collected when `rdd-mocks` is deleted. Given the ownership bug in finding #1, a direct assertion on namespace ownership would catch regressions.

2. **No test for ContainerNamespace resources.** The `containerNamespaceReconciler` creates ContainerNamespace objects (e.g., `buildkit` in the `rancher-desktop` namespace), but no test verifies their existence. If the reconciler fails silently, nothing catches it.

3. **No test for the `pid` optional change.** The CRD change is mechanical and low-risk, but a test creating a Container without a `pid` value would confirm the CRD accepts it.

### Documentation Assessment

No documentation gaps. The constants `apiNamespace` and `containerNamespace` in `mock_controller.go:24-28` are well-commented, and the inline comments in the reconcilers explain their purpose.

---

### Codex GPT 5.4

### Executive Summary

3 commits: `513f44d` makes `ContainerStatus.pid` optional, `7ce6b31` moves mock resources into the `rancher-desktop` Kubernetes namespace, and `29d5ae6` expands mock `ContainerNamespace` creation based on the volume test data.

This should not merge as-is. The new Kubernetes-namespace reconciler introduced in `7ce6b31` can reconcile `rancher-desktop` as both the owner and the owned namespace, which makes the namespace owner reference nondeterministic and occasionally wrong.

### Findings

**Important Issues**

1. **`rancher-desktop` can become self-owned** — `pkg/controllers/mock/kube_namespace_reconciler.go:31-55,65-79` `(important, regression)`

```go
if _, ok := object.(*corev1.Namespace); ok {
	switch object.GetName() {
	case mockNamespaceName, apiNamespace:
		return true
	}
}

ownerReference := metav1apply.OwnerReference().
	WithName(rddNamespace.GetName()).
	WithUID(rddNamespace.GetUID())

corev1apply.Namespace(apiNamespace).
	WithOwnerReferences(ownerReference)
```

`SetupWithManager()` at line 65 watches `Namespace` objects directly, and the filter at lines 75-79 admits both `rdd-mocks` and `rancher-desktop`. `Reconcile()` then reads whichever namespace triggered the request at lines 31-45 and unconditionally writes that namespace as the owner of `Namespace(apiNamespace)` at lines 49-52. When the reconcile is triggered for `rancher-desktop`, lines 31-45 load `rancher-desktop` itself, so lines 49-52 rewrite `rancher-desktop` with an ownerReference pointing back to `rancher-desktop`. I verified this live against a local `rdd svc` control plane: after starting `mock-controller`, `rdd ctl get namespace rancher-desktop -o yaml` showed `ownerReferences.name: rancher-desktop`; after later events it flipped back to `rdd-mocks`, so the owner is currently event-order dependent.

Fix: do not reconcile `apiNamespace` as a primary watched object. The minimal fix is to filter `For(&corev1.Namespace{})` down to `mockNamespaceName` only, or early-return unless `req.Name == mockNamespaceName`, and always build the ownerReference from an explicit fetch of `rdd-mocks`.

### Design Observations

1. **The extra namespace controller is solving a static-object problem with a self-referential watch graph** `(in-scope)`

There is only one Kubernetes namespace to ensure: `rancher-desktop`. Creating or reconciling that namespace from the existing `rdd-mocks`-driven path would remove the `Namespace -> Namespace` watch cycle entirely, which in turn eliminates the class of bugs where the target namespace is accidentally treated as the owner. A simpler model is: `createNamespace()` ensures `rdd-mocks`, and a single reconcile keyed off `rdd-mocks` ensures both `rancher-desktop` and the mock CRs beneath it.

### Testing Assessment

1. No test in this PR asserts that the Kubernetes namespace `rancher-desktop` is created with a stable ownerReference to `rdd-mocks`; the updated BATS file only checks for resources inside that namespace.
2. No test exercises namespace churn for `rancher-desktop` while `mock-controller` is running, which is the path that exposed the ownership instability above.
3. No test in this PR covers the `513f44d` API change by creating or updating a `Container` status without `status.pid`.

I could not run the repo's BATS suite here because `bats` is not installed in this environment. I also could not use `go test ./...` as a clean signal because unrelated untracked files in the repo root (`test-owner.go`, `test-condition.go`, `test-short-circuit.go`) make the root package fail to build.

### Documentation Assessment

No blocking documentation issue stood out, but if there is user-facing API documentation for `Container.status.pid`, it should be updated to match the new optional semantics from `513f44d`.

---

### Gemini 3.1 Pro

### Executive Summary

This PR correctly moves mock resources to the `rancher-desktop` namespace, ensures `ContainerNamespace` resources are created for mock volumes, and makes the `pid` field optional in the containers API. However, a logic flaw in the newly introduced `kubeNamespaceReconciler` causes the `rancher-desktop` namespace to overwrite its own `OwnerReference` to point to itself, severing its link to the `rdd-mocks` namespace and causing a resource leak upon mock deletion. The PR should be merged with fixes for this ownership corruption and missing error handling.

### Critical Issues

1. **`apiNamespace` overwrites its own owner reference, preventing garbage collection** — `pkg/controllers/mock/kube_namespace_reconciler.go:27-51` (critical, regression)

```go
		WithEventFilter(predicate.NewPredicateFuncs(func(object client.Object) bool {
			if _, ok := object.(*corev1.Namespace); ok {
				switch object.GetName() {
				case mockNamespaceName, apiNamespace:
					return true
				}
			}
			return false
		})).
```

Because `apiNamespace` ("rancher-desktop") is allowed by the event filter and the controller enqueues requests directly `For(&corev1.Namespace{})`, updates to `rancher-desktop` trigger a reconcile where `req.NamespacedName` is `"rancher-desktop"`. In `Reconcile`, the controller fetches the requested namespace, constructs an owner reference using its UID, and applies it to `"rancher-desktop"`. Using Server-Side Apply with the same `FieldManager` causes the list to be overwritten, replacing the ownership link to `rdd-mocks` with a link to itself. Consequently, when `rdd-mocks` is deleted, `rancher-desktop` will be orphaned and fail to garbage-collect.

**Fix:** In `Reconcile`, return early if the request is not for the controller's intended owner target:
```go
	if req.Name != mockNamespaceName {
		return ctrl.Result{}, nil
	}
```
*(Alternatively, remove `apiNamespace` from the `WithEventFilter` if `Watches` with `EnqueueRequestForOwner` is sufficient for tracking its deletion).*

### Important Issues

1. **Unhandled `IsNotFound` error causes infinite retry loops on deletion** — `pkg/controllers/mock/kube_namespace_reconciler.go:31-34` (important, gap)

```go
	var rddNamespace corev1.Namespace
	if err := r.Client.Get(ctx, req.NamespacedName, &rddNamespace); err != nil {
		log.Error(err, "Failed to get namespace", "namespace", req.NamespacedName)
		return ctrl.Result{}, err
	}
```

If the watched namespace (`rdd-mocks`) is deleted, `Get` will fail with a Kubernetes `IsNotFound` error. Because this error is returned directly, `controller-runtime` will continuously requeue the request with exponential backoff forever, polluting the logs and wasting CPU cycles.

**Fix:** Ignore the `IsNotFound` error to stop the retry loop, as Kubernetes owner-based garbage collection handles the cleanup of owned resources automatically upon deletion:
```go
	if err := r.Client.Get(ctx, req.NamespacedName, &rddNamespace); err != nil {
		if apierrors.IsNotFound(err) {
			return ctrl.Result{}, nil
		}
		log.Error(err, "Failed to get namespace", "namespace", req.NamespacedName)
		return ctrl.Result{}, err
	}
```
*(Note: This error-handling gap also exists in the other mock reconcilers such as `container_namespace_reconciler.go`, `container_reconciler.go`, etc., and should ideally be fixed for all of them.)*

### Design Observations

- **(in-scope) Future-proofing in `volume_reconciler`:** The loop introduced in `pkg/controllers/mock/container_namespace_reconciler.go` aggregates namespaces from all mock volumes. However, `getVolumeName` in `pkg/controllers/mock/volume_reconciler.go:42` currently hardcodes the return value to `"buildkit"`. While this structure works correctly and creates the expected `"buildkit"` `ContainerNamespace` today, Moby `Volume` objects do not natively expose a namespace concept. If test volumes are intended to exist in multiple namespaces in the future, `getVolumeName` will need a way to parse this data (e.g., via labels or name conventions) before this loop provides dynamic utility.

### Testing Assessment

1. **Untested scenario (High Risk):** Deletion lifecycle and Garbage Collection. The BATS tests correctly verify the creation of resources in the `rancher-desktop` namespace. However, there is no test verifying that deleting the `rdd-mocks` namespace correctly cascade-deletes the `rancher-desktop` namespace and its mock resources. The absence of a deletion test is what allowed the self-ownership regression to slip through.

### Documentation Assessment

The removal of `- pid` from the `required` list in `crd.yaml` and the addition of `+optional` in `pkg/apis/containers/v1alpha1/container_types.go` are self-documenting for CRD regeneration and align correctly. No further documentation updates are needed.
