[Declarative Validation] Track beta→stable graduation of validation rules
What would you like to be added?
A tracking issue for the beta→stable graduation of declarative validation rules, per KEP-5073.
Every DV rule currently at beta carries since: "1.37", and there are no older ones, so nothing was eligible until v1.37 shipped. It has, which opens the wave.
Scope
Settled in this comment:
- One API type per PR, not one group. The type is the kind: a nested struct such as
IPBlockgoes withNetworkPolicy, not in a PR of its own. Deleting handwritten validation has no per-rule rollback and costs the mismatch comparison its baseline, so diffs stay small enough to read line by line. +k8s:betato stable only. Dropping the prefix.+k8s:alphapromotion is out of scope and handled separately.meta/ ObjectMeta is out of scope and tracked separately. This catches whole rows:lifecycle's two rules are both on the embeddedmetav1.ObjectMeta(lifecycle/v1alpha1/types.go:59and:251), so that group is not claimable here.
The group rows below size the backlog. The unit of work, and of claiming, is a single API type inside one of them.
Backlog
Regenerated at 451ab1d9b7c:
| API group | beta rules | Status | Owner | PR |
|---|---|---|---|---|
resource |
410 | unclaimed | ||
flowcontrol |
40 | unclaimed | ||
rbac |
21 | in review | @itzPranshul | #141605 |
networking |
20 | partly claimed | @liyuerich | NetworkPolicy (6). IngressClass (6) and IPAddress (8) unclaimed |
storage |
12 | in review | @itzPranshul | #142056 (VolumeAttachment). #141967 (StorageClass) merged 2026-09-15 |
certificates |
12 | in review | @antcybersec | #142333 (CertificateSigningRequest) |
autoscaling |
12 | in review | @datayurei | #142151 (HorizontalPodAutoscaler, 10). The other 2 are Scale, see apps |
extensions |
8 | not workable | no pkg/apis/extensions/validation/ exists, so there is nothing to delete; extensions/v1beta1 is the one entry in coverage-allowlist.yaml, "Not served by kube-apiserver" |
|
admissionregistration |
6 | in review | @alinaqvi1129 | #142222 (ValidatingAdmissionPolicyBinding) |
apps |
4 | unclaimed | all four are ScaleSpec.replicas in v1beta1/v1beta2. They graduate together with autoscaling/v1 Scale as one PR: 6 rules, one handwritten check in ValidateScale |
|
core |
2 | out of scope | @yongruilin | #141564 (ReplicationControllerSpec, merged). The remaining 2 are on ReplicationController's metav1.ObjectMeta |
lifecycle |
2 | out of scope | both rules are on metav1.ObjectMeta, see Scope |
|
node |
0 | done | @krishhna24 | #142119 (RuntimeClass, merged 2026-09-16) |
discovery |
0 | done | @krishhna24 | #141533 (EndpointSlice, merged 2026-09-03) |
batch |
0 | done | @alinaqvi1129 | #141677 (CronJob, merged 2026-09-14) |
| total | 549 |
authorization, scheduling, policy and storagemigration carry alpha rules only, so they have nothing to graduate here.
Counts move as the wave lands. The total was 592 at filing, then 588, then 574 after #141533 (discovery) and #141677 (batch), and is 549 now: #141967 took storage 28 to 12 and #142119 took node 9 to 0. Only types.go carries the markers, so this returns the same number:
grep -rho --include='*.go' '+k8s:beta(since:' staging/src/k8s.io/api | wc -lClaiming
Comment here naming the API type you are taking, then open one PR for it. I will keep the table current.
On sourcing Owner from the tag's owner: field: that field does not exist. +k8s:alpha and +k8s:beta accept at most one argument and it has to be since, matching a version regex, so anything else is a generator error (staging/src/k8s.io/code-generator/cmd/validation-gen/validators/levels.go:64-74). A grep -rho 'owner:' staging/src/k8s.io/api returns nothing. So Owner comes from claims in this thread instead, unless you would rather the tag grew the field.
Why is this needed?
The KEP's criteria for beta→stable are ">=1 release at Beta, zero mismatch/panic metrics, reviewers agree the safety switch is no longer needed", and "the same PR removes the matching handwritten validation".
The first two are checkable in-tree. pkg/api/testing/validation.go already asserts apiserver_validation_declarative_validation_mismatch_total == 0 under both gate configurations, so a graduation can be verified locally rather than from production dashboards.
The third is a reviewer judgement, which is why this is an issue and not just a series of PRs.
Worth writing down
Dropping the wrapper and deleting the handwritten check are not separable. FilterCoveredHandwrittenErrors only suppresses a handwritten error when a matching beta declarative error is enforced, so a graduated rule that still has its handwritten twin reports the same violation twice and trips the mismatch metric. Demonstrated in #141533.
/sig api-machinery /area api-validation /kind cleanup
Source: kubernetes/kubernetes