ProxyClass and other Tailscale CRDs embed corev1 types (e.g. corev1.Affinity)
whose sibling fields are declared as type: object in the generated OpenAPI
schema. Under server-side apply (ArgoCD, Flux), unset sibling fields are sent
as null, but the API server rejects null for type: object without nullable: true.
This does not affect native Kubernetes types because the API server handles
those with built-in logic rather than OpenAPI schema validation.
Fix this with a two-layer approach:
1. Add // +nullable markers to optional object/array/map fields in our own Go
types (ProxyClass, Recorder, DNSConfig). controller-gen honours these
markers and they survive schemapatch regeneration.
2. Add a post-processing step (crdnullable) that runs after controller-gen to
add nullable: true to optional object/array sub-fields inside embedded
corev1 type subtrees. These sub-fields are defined in Kubernetes core and
cannot be annotated by us. The post-processor identifies corev1 type
schemas by their field signatures (e.g. nodeAffinity + podAffinity +
podAntiAffinity = corev1.Affinity) and only marks optional fields that
don't already have nullable: true.
The post-processor is wired into the go:generate pipeline between
controller-gen and staticmanifests generation.