Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates documentation across the framework, primarily by improving readability/consistency (punctuation, list/table wording) and expanding the narrative explanation of the component model in the main docs.
Changes:
- Refreshes and standardizes wording/punctuation across many primitive docs and core conceptual docs.
- Expands
docs/component.mdandREADME.mdwith more detailed explanations and examples of why/ how to structure operators with components. - Tweaks tables and ordered lists for consistent formatting.
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/primitives/unstructured.md | Wording and table tweaks for unstructured primitive docs |
| docs/primitives/serviceaccount.md | Punctuation/table wording tweaks |
| docs/primitives/service.md | Minor punctuation update in suspension section |
| docs/primitives/secret.md | Punctuation/table wording tweaks; minor rephrasing |
| docs/primitives/rolebinding.md | Punctuation tweak in capabilities table |
| docs/primitives/role.md | Punctuation/table wording tweaks; minor rephrasing |
| docs/primitives/replicaset.md | Minor punctuation tweak in intro |
| docs/primitives/pvc.md | Capabilities/table wording tweaks; punctuation changes |
| docs/primitives/pv.md | Capabilities/table wording tweaks |
| docs/primitives/pod.md | Minor rephrasing for clarity in “Raw” and suspension bullets |
| docs/primitives/pdb.md | Capabilities wording tweaks; punctuation change in method description |
| docs/primitives/networkpolicy.md | Capabilities wording tweaks; minor rephrasing in mutation explanation |
| docs/primitives/job.md | Minor punctuation tweak in intro |
| docs/primitives/ingress.md | Capabilities wording tweaks; reflowed guidance bullets |
| docs/primitives/hpa.md | Minor punctuation/reflow tweaks |
| docs/primitives/deployment.md | Minor punctuation/reflow tweaks |
| docs/primitives/daemonset.md | Minor wording tweak in grace-status table |
| docs/primitives/cronjob.md | Minor punctuation tweaks |
| docs/primitives/configmap.md | Table wording tweaks; punctuation/reflow in hashing/guidance sections |
| docs/primitives/clusterrolebinding.md | Capabilities/table wording tweaks |
| docs/primitives/clusterrole.md | Punctuation tweaks; table wording tweaks |
| docs/primitives.md | Punctuation/style consistency updates across core primitives doc |
| docs/custom-resource.md | Rewording/reflow; minor comment punctuation tweak |
| docs/component.md | Significant expansion of “why components” narrative + wording/style consistency |
| README.md | Expanded overview narrative; minor phrasing tweaks; removes “Project Structure” section |
| ## Overview | ||
|
|
||
| Kubernetes operators tend to accumulate complexity over time: reconciliation functions grow large, lifecycle logic is | ||
| duplicated across resources, status reporting becomes inconsistent, and version-compatibility code gets tangled into | ||
| orchestration. The Operator Component Framework addresses these problems through a clear layered architecture. | ||
|
|
||
| The framework organizes operator logic into three composable layers: | ||
|
|
||
| - **Components** — logical feature units that reconcile multiple resources together and report a single user-facing | ||
| condition. | ||
| - **Resource Primitives** — reusable, type-safe wrappers for individual Kubernetes objects with built-in lifecycle | ||
| semantics. | ||
| - **Feature Mutations** — composable, version-gated modifications that keep baseline resource definitions clean while | ||
| managing optional and historical behavior explicitly. | ||
| Every Kubernetes operator starts simple: a reconciler, a few resources, some status updates. Then reality sets in. The | ||
| reconciler grows into a monolith where creation, update, health-checking, suspension, and version-compatibility logic | ||
| are all interleaved in a single function. Lifecycle behavior gets copy-pasted across resources because there is no | ||
| shared abstraction for "a deployment that can be suspended" or "a job that runs to completion." Status reporting drifts: | ||
| one resource sets a condition, another logs a warning, a third does nothing. And when you need to support multiple | ||
| product versions, compatibility shims get wired directly into orchestration code, making it impossible to reason about | ||
| what the baseline behavior actually is. | ||
|
|
||
| The Operator Component Framework exists because these problems are structural, not incidental. They cannot be solved by | ||
| writing more careful code in the same flat reconciler model. They require a different organizational unit for operator | ||
| logic. | ||
|
|
||
| The framework introduces three composable layers that separate concerns that operators routinely conflate: | ||
|
|
||
| - **Components** are logical feature units that reconcile multiple resources together and report a single user-facing | ||
| condition. A component is the answer to "what does this feature need, and is it healthy?" | ||
| - **Resource Primitives** are reusable, type-safe wrappers for individual Kubernetes objects with built-in lifecycle | ||
| semantics. A primitive knows how to create, update, suspend, and report health for its resource, so your reconciler | ||
| does not have to. | ||
| - **Feature Mutations** are composable, version-gated modifications that keep baseline resource definitions clean. | ||
| Instead of scattering `if version < X` checks throughout your reconciler, mutations declare their applicability and | ||
| are applied in a predictable sequence. |
There was a problem hiding this comment.
The PR title is “update readme”, but this change set updates many other documentation files under docs/ as well. Consider renaming the PR to reflect the broader scope (e.g., “docs: punctuation/clarity updates” or similar) so reviewers and release notes consumers aren’t misled.
| | Variant | Required at `Build()` | Optional | | ||
| | --------------- | --------------------- | -------------------------------------------------------- | | ||
| | **Static** | _(none)_ | — | | ||
| | **Static** | _(none)_ | All optional | | ||
| | **Workload** | `ConvergingStatus` | `GraceStatus` (defaults to Healthy), suspension handlers | |
There was a problem hiding this comment.
In the “Required Handlers per Variant” table, the Static unstructured builder doesn’t have any status/suspension handlers (it only supports mutations and data extractors), so listing “All optional” under Optional is misleading. Consider changing this cell to “—” / “(none)” or explicitly calling out only data extraction/mutations for the static variant.
| | Option | Behavior | | ||
| | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `ResourceOptions{}` (default) | **Managed**: created or updated; health contributes to condition | | ||
| | `ResourceOptions{ReadOnly: true}` | **Read-only**: fetched but never modified; health still contributes | | ||
| | `ResourceOptions{Delete: true}` | **Delete-only**: removed from the cluster if present; does not contribute to health | | ||
| | `ResourceOptions{ParticipationMode: ParticipationModeAuxiliary}` | The resource's health does not contribute to the component condition. The component can become Ready regardless of this resource's state | |
There was a problem hiding this comment.
The ResourceOptions example in this table isn’t valid as written for consumers (it omits the component. qualifier, and ParticipationModeAuxiliary is also unqualified). To keep the docs copy/pasteable, use component.ResourceOptions{...} and component.ParticipationModeAuxiliary (matching the code sample above).
| | Option | Behavior | | |
| | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | |
| | `ResourceOptions{}` (default) | **Managed**: created or updated; health contributes to condition | | |
| | `ResourceOptions{ReadOnly: true}` | **Read-only**: fetched but never modified; health still contributes | | |
| | `ResourceOptions{Delete: true}` | **Delete-only**: removed from the cluster if present; does not contribute to health | | |
| | `ResourceOptions{ParticipationMode: ParticipationModeAuxiliary}` | The resource's health does not contribute to the component condition. The component can become Ready regardless of this resource's state | | |
| | Option | Behavior | | |
| | ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | |
| | `component.ResourceOptions{}` (default) | **Managed**: created or updated; health contributes to condition | | |
| | `component.ResourceOptions{ReadOnly: true}` | **Read-only**: fetched but never modified; health still contributes | | |
| | `component.ResourceOptions{Delete: true}` | **Delete-only**: removed from the cluster if present; does not contribute to health | | |
| | `component.ResourceOptions{ParticipationMode: component.ParticipationModeAuxiliary}` | The resource's health does not contribute to the component condition. The component can become Ready regardless of this resource's state | |
| @@ -91,7 +91,7 @@ type FeatureMutator interface { | |||
| ``` | |||
|
|
|||
| `Apply()` executes all recorded mutations against the underlying object. `NextFeature()` advances to a new feature scope | |||
There was a problem hiding this comment.
There’s a punctuation/formatting issue here: the sentence ending with “NextFeature() advances to a new feature scope” is missing a trailing period, and the following sentence starts on a new line without a paragraph break. Add the period (and optionally join/wrap the sentences) to keep the prose grammatically correct.
| `Apply()` executes all recorded mutations against the underlying object. `NextFeature()` advances to a new feature scope | |
| `Apply()` executes all recorded mutations against the underlying object. `NextFeature()` advances to a new feature scope. |
No description provided.