* Add etcd_bookmark_total counter metric and deprecate etcd_bookmark_counts
* Update docs using scripts
* Add test for etcd_bookmark_total and run gofmt
* gofmt
- Code generator: use len() != 0 for slice/map member extractors
instead of != nil, so empty slice/map are treated as "not set"
- Add slice and map members to union test types (both discriminated
and undiscriminated)
- Add test coverage for nil vs empty, ratcheting, and nil oldObj
with slice/map members
Co-authored-by: Tim Hockin <thockin@google.com>
- Use reflect.ValueOf(oldObj).IsZero() instead of IsNil() so union
validation works with non-nilable T (e.g. value types)
- Remove hasOldValue guard from inner loop conditionals; only check
at the final ratcheting skip point
- Add doc comments explaining T is "any" rather than "comparable"
because union members can be slices
- Add value-type subtests for Union and DiscriminatedUnion
Co-authored-by: Tim Hockin <thockin@google.com>
Removed split-brain subscriber interface and switched to purely PodWorker broadcasting immediately after SetPodStatus to ensure consistent, monotonic view of the pod.
For ADDED, we broadcast directly after receiving the pod info and successfully processing it for the first time from the API server, so this should always be the first thing broadcast for a given pod.
For DELETED, we broadcast after it has been processed in updateStatusInternal with podIsFinished, so this should always be the last thing broadcast for a given pod.
For MODIFIED, we broadcast once when we receive a new spec from the API server, and once when we finish processing in the status manager. This way the watchers can see the flow from when a spec is received to when it has reconciled. To avoid status flapping on slow status updates with many spec updates, we always overlay the latest status from the status manager on every broadcast. This hybrid state is fine because the ObservedGeneration will indicate how far desynced the spec has become from the status, so watchers can act accordingly.
- Fixed version in kube_features.go after rebase (1.35->1.36)
- Removed internal pod cache in PodsServer to reduce memory footprint and avoid duplication.
- Injected pod.Manager into PodsServer to serve as the single source of truth for pod data.
- Refactored WatchPods to broadcast UIDs and fetch fresh pod data from podManager, ensuring consistency.
- Updated convertWatchEventType to safely handle unknown event types.
- Refactored unit tests to use MockManager and added a test case for static pods.
- Updated e2e suite with static pod test
Test that declarative validation catches a DeviceAttribute with no
value fields set, which was the original bug scenario where union
ratcheting incorrectly skipped validation for new map entries.
Add tests for Union, DiscriminatedUnion, and ZeroOrOneOfUnion
validating that nil oldObj (new map entry or newly-set pointer
field during update) does not skip validation via ratcheting.
When oldObj is nil (e.g. new map entry added during update), union
ratcheting incorrectly treats nil old and empty new as unchanged
membership, skipping validation entirely. Fix by checking
reflect.ValueOf(oldObj).IsNil() and disabling ratcheting when
oldObj is nil, so the new value is fully validated.
This affects Union, DiscriminatedUnion, and ZeroOrOneOfUnion
(via unionValidate).