feat(meta): add lifecycle-state annotation contract#1
Merged
Conversation
Adds the typed contract for vk-cocoon's lifecycle-state annotation triple
plus the cocoonset-generation bridge cocoon-operator stamps onto pods so
vk-cocoon can write it back as observed-generation. Counter-based, not
clock-based, per K8s API conventions.
- LifecycleState / LifecycleStatus with Apply / PatchPayload / Snapshot
- AnnotationLifecycleState{,ObservedGeneration,Message}
- AnnotationCocoonSetGeneration + StampCocoonSetGeneration
- PatchCocoonSetGeneration helper, mirror of PatchHibernateState
This was referenced May 10, 2026
- Apply now consumes PatchPayload directly so the in-memory and patch paths cannot drift; eliminates the need for a mirror-invariant test. - Group IsTerminal with LifecycleState; drop the state list from its godoc (would rot when terminal states change). - Extract readInt64Annotation to dedupe the two int64 annotation parsers. - Cover Apply, PatchPayload, Snapshot, ReadLifecycleStatus, and StampCocoonSetGeneration (previously had only IsTerminal and Read*State coverage).
- Lists LifecycleStatus alongside the other typed annotation contracts. - Adds generation / lifecycle-* keys to the identifier-namespace tables. - Explains the counter-based completion design so consumers know which helpers cooperate (StampCocoonSetGeneration on the operator side, ReadCocoonSetGeneration + LifecycleStatus on the vk-cocoon side).
There was a problem hiding this comment.
Pull request overview
Adds a typed, shared contract for a Pod lifecycle-state annotation triple (state / observed-generation / message) and introduces a CocoonSet generation “bridge” annotation plus a helper for stamping it onto Pods, so downstream components can reliably publish/observe completion using a counter rather than wall-clock markers.
Changes:
- Define
LifecycleState/LifecycleStatushelpers for writing, reading, patch-payload generation, and drift snapshots of lifecycle annotations. - Add
cocoonset.cocoonstack.io/generationannotation key and helpers to read/stamp it. - Add
k8s.PatchCocoonSetGenerationhelper + tests mirroring the existing hibernate patch helper.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| meta/meta.go | Adds new annotation key constants for lifecycle state and CocoonSet generation. |
| meta/lifecycle.go | Implements the lifecycle-state typed contract, read/write helpers, and int64 parsing utilities. |
| meta/lifecycle_test.go | Adds unit tests for lifecycle helpers and snapshot stability. |
| k8s/utils.go | Adds PatchCocoonSetGeneration helper for patching the generation annotation. |
| k8s/utils_test.go | Adds tests for PatchCocoonSetGeneration and fixes minor formatting in existing tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Mirror PatchHibernateState by routing the short-circuit through ReadCocoonSetGeneration, which tolerates a nil pod. Also normalizes the comparison to the parsed int64 so a malformed annotation does not force a redundant patch when the desired generation matches the parsed value. Names the IsTerminal subtests explicitly so the empty-state case shows up readably instead of as the synthesized #00.
The method returns the annotation key/value map (with nil meaning delete), not a complete apiserver patch body — callers still need to wrap it via k8s.AnnotationsMergePatch (or embed under .metadata.annotations). The previous name and godoc invited the misuse of feeding the bare return value to a Patch call. README example now shows the wrap-with-AnnotationsMergePatch link explicitly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
vm.cocoonstack.io/lifecycle-stateannotation triple (state, observed-generation, message) —LifecycleStatus.Apply/PatchPayload/Snapshotkeep the in-memory pod, the apiserver patch body, and the drift-comparison key in sync.cocoonset.cocoonstack.io/generationbridge that cocoon-operator stamps onto every owned pod so vk-cocoon can read it back aslifecycle-observed-generation. Counter-based completion signal — K8s API conventions explicitly recommend against wallclock-based markers (k/k#29229, k/k#119514 are the canonical case studies).PatchCocoonSetGenerationhelper, structurally identical to existingPatchHibernateState.Why
vk-cocoon today has no way to publish "operation X actually finished" externally.
cocoonset.status.phase=Suspendedis set eagerly whenEpoch.HasManifestreturns true — which fires on stale tags from a previous hibernate, so a hibernate2-then-wake cycle on a recently-hibernated VM short-circuits and serializes against the still-running first snapshot push. This contract gives the writer (vk-cocoon) and the reader (clients via Pod annotation) a stable counter-based completion API that does not depend on wall clocks.Full design in
cocoonstack/cocoon-specs#feat/lifecycle-state-annotation(design/lifecycle-state-contract.md).Test plan
go test -race ./...passesmake lintclean on bothGOOS=linuxandGOOS=darwinvk-cocoonwriter +cocoon-operatorbridge) bump to a pseudo-version pointing at the merged commit before they merge