[DOCS#EV-6623]: Fill HEP policy recommendation docs gaps — selector syntax and status lifecycle#2734
Conversation
…lifecycle Backfill two release-blocking gaps surfaced in EV-6623 against the HEP policy recommendation docs merged in tigera#2658. hostEndpointSpec.selector had no Calico selector operator reference. Add a "Scope recommendations to specific hosts" section on the HEP page with a worked example and a common-pattern table, plus a "Selectors" section on the PolicyRecommendationScope reference page rendering the existing <Selectors /> partial that was imported but unused. The policyrecommendation.tigera.io/status annotation lifecycle (Learning -> Stabilizing -> Stable) was undocumented. Add a "Track recommendation readiness" section on the HEP page with kubectl one-liners and a tip to wait for Stable before enforcing, and a paired "Annotations on generated recommendations" / "Recommendation status lifecycle" pair on the reference page that documents the full annotation family and the transitions driven by lastUpdated, interval, and stabilizationPeriod. Refs EV-6623.
✅ Deploy Preview for calico-docs-preview-next ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview succeeded!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
This PR backfills missing Calico Enterprise “next” documentation for the host policy recommendation feature by adding (1) selector/operator syntax guidance for hostEndpointSpec.selector and (2) the engine-driven recommendation readiness lifecycle (Learning → Stabilizing → Stable) tied to policyrecommendation.tigera.io/status.
Changes:
- Adds a new “Selectors” section to the PolicyRecommendationScope reference and links HostEndpoint selector docs to it.
- Documents the
policyrecommendation.tigera.io/*annotation family and status lifecycle transitions on generated recommendations. - Updates the host policy recommendations how-to with host scoping examples and kubectl commands to read readiness status.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| calico-enterprise/reference/resources/policyrecommendations.mdx | Adds selectors reference rendering plus new annotation/status lifecycle documentation; links HostEndpoint selector field to the selectors section. |
| calico-enterprise/network-policy/recommendations/hep-policy-recommendations.mdx | Adds “scope by selector” guidance and a “track readiness” section with status meanings and kubectl JSONPath examples. |
Comments suppressed due to low confidence (1)
calico-enterprise/reference/resources/policyrecommendations.mdx:108
- The new “Selectors” section states it applies to both
namespaceSpecandhostEndpointSpec, but only the HostEndpointSpec table’sselectorrow links readers to#selectors. To avoid leaving the namespace selector without operator syntax guidance, either add the same#selectorsreference to the NamespaceSpecselectorrow or adjust this section text to only claim coverage for the fields that link here.
## Selectors
The `selector` fields on `namespaceSpec` and `hostEndpointSpec` accept
the same label-selector expression language used elsewhere in Calico
network policy.
| | Annotation | Description | | ||
| | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `policyrecommendation.tigera.io/status` | Engine's readiness signal for this recommendation. See [Recommendation status lifecycle](#recommendation-status-lifecycle) below. | | ||
| | `policyrecommendation.tigera.io/lastUpdated` | RFC 3339 timestamp of the engine's last modification to the recommendation's spec. Drives the `Learning → Stabilizing → Stable` transitions. | | ||
| | `policyrecommendation.tigera.io/scope` | Scope the recommendation was generated for. One of `namespace` (namespace recommendations) or `hostEndpoint` (host recommendations). Individual rules can also carry per-rule `scope` annotations such as `Domains`, `Private`, `Public`, `Service`, `NetworkSet`. | | ||
| | `policyrecommendation.tigera.io/name` | Name of the source object (namespace for namespace recommendations, HostEndpoint for host recommendations). | | ||
| | `policyrecommendation.tigera.io/namespace` | For namespace recommendations: the namespace the recommendation applies to. | | ||
|
|
||
| ### Recommendation status lifecycle | ||
|
|
||
| The `policyrecommendation.tigera.io/status` annotation moves through | ||
| the following values as the engine refines a recommendation. The | ||
| transitions are driven by `lastUpdated`: the longer the spec has | ||
| remained unchanged, the further the recommendation has progressed. | ||
|
|
||
| | Status | When it is set | | ||
| | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `Learning` | Initial value for every new recommendation. Reset to this whenever the engine modifies the spec. | | ||
| | `Stabilizing` | Set when the spec has been unchanged for more than `2 × interval` but no more than `stabilizationPeriod`. Rules look settled but are still being watched. | | ||
| | `Stable` | Set when the spec has been unchanged for more than `stabilizationPeriod`. Treat as ready to accept and enforce. | | ||
|
|
||
| `interval` and `stabilizationPeriod` are the top-level fields on this | ||
| resource. Adjusting them directly controls how quickly a recommendation | ||
| can reach `Stable`. See [Spec](#spec). | ||
|
|
||
| The engine resets the status to `Learning` and bumps `lastUpdated` any | ||
| time it adds, removes, or changes a rule, so a recommendation that | ||
| absorbs new traffic late in its life cycle returns to `Learning` until | ||
| it next stabilizes. |
| | Value | Meaning | | ||
| | ------------- | ---------------------------------------------------------------------------------------------------------------------------- | | ||
| | `Learning` | Engine is still actively adding or modifying rules from flow logs. This is the initial value and is reset whenever the engine changes the recommendation. | | ||
| | `Stabilizing` | Engine has not modified the recommendation for longer than `2 × interval`, but less than `stabilizationPeriod`. Rules look settled but the engine is still watching. | |
ctauchen
left a comment
There was a problem hiding this comment.
Some suggestions for you, thanks for this!
|
|
||
| ### Scope recommendations to specific hosts | ||
|
|
||
| By default, every HostEndpoint in the cluster is eligible for |
There was a problem hiding this comment.
| By default, every HostEndpoint in the cluster is eligible for | |
| By default, every host endpoint in the cluster is eligible for |
There was a problem hiding this comment.
When describing generically, use a normal phrase like "host endpoint." Otherwise, use the terms as a modifier in code font: "a HostEndpoint resource."
| By default, every HostEndpoint in the cluster is eligible for | ||
| recommendations. To restrict the engine to a subset, set | ||
| `hostEndpointSpec.selector` to a Calico label-selector expression that | ||
| matches the HostEndpoint labels you want to cover. |
There was a problem hiding this comment.
perhaps "matches the labels of the host endpoint you want to cover."
| "spec": { | ||
| "hostEndpointSpec": { | ||
| "recommendationStatus": "Enabled", | ||
| "selector": "environment == '\''prod'\''" |
There was a problem hiding this comment.
Just checking, are the escape characters here related to docs site pagination? Or is this exactly how it's meant to be in code?
|
|
||
| A few common patterns: | ||
|
|
||
| | Goal | Expression | |
There was a problem hiding this comment.
If the header is "Goal", then I feel like the column cells should have some sort of embedded action. Match all host endpoints, Match only a single label value, etc.
Alternatively, you can modify the header. Something like "Match target".
| }' | ||
| ``` | ||
|
|
||
| A few common patterns: |
There was a problem hiding this comment.
| A few common patterns: | |
| This table shows common selector patterns host endpoint policy recommendations: |
Something like this, to be more specific and descriptive about what's in the table.
| global network policy. Use it to know when a recommendation has settled | ||
| down enough to enforce. |
There was a problem hiding this comment.
Not clear what you mean by 'settled down'.
| The status transitions are driven by the time since the engine last | ||
| modified the recommendation, not by elapsed time alone: | ||
|
|
||
| - A host that suddenly sends new traffic mid-`Stabilizing` will be |
There was a problem hiding this comment.
mid-Stabilizing
during a Stabilizing period, perhaps?
There was a problem hiding this comment.
will be knocked back --> returns to Learning
| Wait for `Stable` before | ||
| [accepting](#activate-a-recommendation) and | ||
| [enforcing](#enforce-a-recommendation) a recommendation. Accepting a | ||
| recommendation while it is still `Learning` or `Stabilizing` pins the |
There was a problem hiding this comment.
| recommendation while it is still `Learning` or `Stabilizing` pins the | |
| recommendation while it is still learning or stabilizing pins the |
HEP page (hep-policy-recommendations.mdx): - Use plain "host endpoint" in generic prose; reserve `HostEndpoint` for the resource name (Chris). - Reword "matches the HostEndpoint labels you want to cover" to "matches the labels of the host endpoints you want to cover" (Chris). - Replace the inline kubectl patch that needed shell single-quote escapes (`'\''`) with a `--patch-file=/dev/stdin` heredoc carrying a YAML patch. Removes the escape question entirely (Chris). - Introduce the selector-pattern table with a descriptive sentence (Chris). - Rewrite the pattern-table "Goal" cells as imperatives that match the column header (Chris). - Replace "settled down enough to enforce" with "stopped changing long enough to be ready to enforce" (Chris). - Add an introductory sentence before the status-annotation table (Chris). - Tighten the Stabilizing row boundary from "but less than stabilizationPeriod" to "but no more than stabilizationPeriod" so it matches the source check `diff <= rec.stabilization` and the wording on the reference page (Copilot). - Replace "mid-Stabilizing will be knocked back" with "during a Stabilizing period returns to" (Chris). - Lowercase `Learning`/`Stabilizing` in the tip's prose so they read as states, not literals (Chris). Reference page (policyrecommendations.mdx): - Clarify that `lastUpdated` tracks the generated staged policy's spec, not the PolicyRecommendationScope spec (Copilot). - Apply the same clarification to the lifecycle intro that referenced "the spec" (Copilot). - Link the NamespaceSpec `selector` row to the new `#selectors` anchor so both selectors are reachable from the section that claims to document both (Copilot). Refs EV-6623.
|
LGTM for me. Need other approvals or ready to merge? @electricjesus |
|
Thanks @ctauchen! I will wait for @xiumozhan to confirm first |

Product Version(s):
Calico Enterprise (next / unreleased — applies to the docs merged in #2658).
Issue:
Link to docs preview:
Once Netlify builds, the two updated pages are:
/calico-enterprise/next/network-policy/recommendations/hep-policy-recommendations/calico-enterprise/next/reference/resources/policyrecommendationsSummary
Backfills two release-blocking gaps surfaced during the CNX-R1355 / CNX-T5996 manual test cycle audit of #2658.
1.
hostEndpointSpec.selectorhad no operator syntax referenceNeither the HEP page nor the PolicyRecommendationScope reference page documented the Calico label-selector syntax (
==,in {…},has(),all(), boolean composition, …) that the field accepts. A user landing onhostEndpointSpec.selectorfor the first time had no path to the operator reference.Changes:
### Scope recommendations to specific hostssection with a worked example (environment == 'prod') and a common-pattern table, linking to the new selectors anchor on the reference page.## Selectorssection that renders the<Selectors />partial — the import was already at the top of the file but never rendered.selectorrow in the HostEndpointSpec table now points at#selectors.2.
policyrecommendation.tigera.io/statuslifecycle was undocumentedThe HEP page describes the user-controlled
stagedActionlifecycle (Learn/Set/Ignore), and mentionsstabilizationPeriodonly as a config knob. The engine's own readiness signal — thepolicyrecommendation.tigera.io/statusannotation moving throughLearning → Stabilizing → Stable— wasn't documented anywhere. Users had no way to answerwhen is my recommendation ready to enforce?.Verified against source:
policy-recommendation/pkg/calico-resources/stagednetworkpolicy.go:53-57andpkg/engine/recommendation.go:493-534.Changes:
### Track recommendation readinesssection with the status table, the exact transition conditions (> 2 × interval,> stabilizationPeriod), the reset-on-modify behavior, twokubectlone-liners (single + bulk) for reading the annotation, and a tip to wait forStablebefore accepting/enforcing.## Annotations on generated recommendationssection documenting the fullpolicyrecommendation.tigera.io/*annotation family (status,lastUpdated,scope,name,namespace), plus a### Recommendation status lifecyclesubsection that the HEP page cross-links to.Not in scope
The reference page imports several other partials (
Servicematch,Serviceaccountmatch,Ports,Entityrule,Icmp,Rule) that are never rendered — the page truncates at the HostEndpointSpec table. Looks like a separate gap from the original fork ofglobalnetworkpolicy.mdx. Leaving for a follow-up so this PR stays focused on EV-6623.SME review
Merge checklist
BUILD_NEXT=true yarn buildproduced no new broken-link errors against the two changed pages)