You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: keps/sig-api-machinery/5073-declarative-validation-with-validation-gen/README.md
+38-3Lines changed: 38 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -1024,10 +1024,45 @@ The streamed data does not require declarative validation, as it is not structur
1024
1024
1025
1025
### Ratcheting
1026
1026
1027
-
TODO: Document and explain how:
1027
+
As Kubernetes APIs evolve, validation rules change. To minimize disruption for users with existing objects created under older rules, declarative validation will incorporate **Validation Ratcheting**. This mechanism aims to selectively bypass new or changed validation rules during object updates (`UPDATE`, `PATCH`, `APPLY`) for fields that have not been modified from their previously persisted state.
1028
1028
1029
-
- Add general purpose ratcheting to automatically skip validation of unchanged fields
1030
-
- Catalog and handle complex cases where strict equality checks are not sufficient (lots of non-trivial cases exist today)
1029
+
#### Core Principles
1030
+
1031
+
The design adheres to the following core principles:
1032
+
1033
+
1.**Stored data is considered valid:** Any object successfully persisted was once considered valid. Subsequent apiservers must not retroactively invalidate stored objects. (Implication: fixing validation bugs post-release is challenging).
1034
+
2.**Unchanged fields do not cause update rejections:** An `UPDATE` operation must not fail validation due to fields that were not modified in that operation. (Rationale: HTTP 4xx errors imply a client request problem).
1035
+
3.**Semantic deep-equal is always sufficient to elide re-validation:** Kubernetes API objects adhere to canonical semantic equivalence rules (`equality.Semantic.DeepEqual`). If a deserialized object satisfies that equivalence with its prior state, re-validation can be bypassed.
1036
+
***Subtle:** List elements might individually bypass re-validation, but the list itself might still be re-validated (e.g., if reordered).
1037
+
1038
+
Ratcheting is the **default behavior** during `UPDATE` operations.
1039
+
1040
+
##### Definition of Semantic Equivalence
1041
+
1042
+
"Semantic equivalence" builds on `k8s.io/apimachinery/pkg/api/equality.Semantic.DeepEqual` (similar to `reflect.DeepEqual` but `nil` and empty slices/maps are equivalent). The table below outlines the behavior:
1043
+
1044
+
| Value type | Semantic Equivalence | Ratcheting | CRD Comparison (KEP-4008) |
| Slices | all elements are equivalent and the is order unchanged | revalidate the slice if any element changed or order changed |`listType=map`: no validate when re-order<br/>`listType=set`: re-validate when re-order<br/>`listType=atomic`: re-validate when re-order |
1052
+
| Slice values<br/>`listType=atomic`| - | validate items which are not found (by value) in the old slice | Validate all elements (CRDs ratcheting may be expanded to match in-tree ratcheting) |
1053
+
| Slice values<br/>`listType=map`| - | (re)validate items which are not found (by key) in the old slice or are changed | same |
1054
+
| Slice values<br/>`listType=set`| - | validate items which are not found (by value) in the old slice | Validate all elements (CRDs ratcheting may be expanded to match in-tree ratcheting) |
1055
+
| Maps | all elements are equivalent | revalidate the map if any element changed | same |
1056
+
| Map values<br/>`mapType=granular`| - | (re)validate items which are not found (by key) in the old map | same |
1057
+
| Map values<br/>`mapType=atomic`| - | (re)validate items which are not found (by key) in the old map |[Issue #131566](https://github.com/kubernetes/kubernetes/issues/131566) (Alignment needed) |
1058
+
1059
+
**Note on Atomic Types:** The behavior for `structType=atomic` and `mapType=atomic` intentionally deviates from strict atomic re-validation. Only the specific sub-fields or key-value pairs *that were actually modified* are re-validated. This prioritizes user experience but requires alignment with CRD behavior (tracked in Issue #131566).
1060
+
1061
+
#### Ratcheting and Cross-Field Validation
1062
+
1063
+
A challenge arises if a cross-field validation rule (e.g. `X < Y`) is defined on this common ancestor struct, and an unrelated field (e.g. `Z`) within that same ancestor is modified. This change to `Z` makes the common ancestor “changed” overall, triggering re-validation of the `X < Y` rule. If this rule was recently evolved (e.g., made stricter), it might now fail even if `X` and `Y` themselves are not modified by the user’s update. This could violate the principle “Unchanged fields do not cause update rejections”.
1064
+
1065
+
For the initial implementation, this behavior will be documented, and cross-field validation rules must handle ratcheting themselves. This means that in the initial implementation of dedicated cross-field tags (e.g., `+k8s:unionMember`), their generated code will handle ratcheting of the specific fields they operate on directly.
0 commit comments