Skip to content

[DOCS#EV-6623]: Fill HEP policy recommendation docs gaps — selector syntax and status lifecycle#2734

Open
electricjesus wants to merge 2 commits into
tigera:mainfrom
electricjesus:seth/EV-6623-hep-polrec-docs-fixes
Open

[DOCS#EV-6623]: Fill HEP policy recommendation docs gaps — selector syntax and status lifecycle#2734
electricjesus wants to merge 2 commits into
tigera:mainfrom
electricjesus:seth/EV-6623-hep-polrec-docs-fixes

Conversation

@electricjesus
Copy link
Copy Markdown
Member

@electricjesus electricjesus commented May 20, 2026

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/policyrecommendations

Summary

Backfills two release-blocking gaps surfaced during the CNX-R1355 / CNX-T5996 manual test cycle audit of #2658.

1. hostEndpointSpec.selector had no operator syntax reference

Neither 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 on hostEndpointSpec.selector for the first time had no path to the operator reference.

Changes:

  • HEP page: new ### Scope recommendations to specific hosts section with a worked example (environment == 'prod') and a common-pattern table, linking to the new selectors anchor on the reference page.
  • Reference page: new ## Selectors section that renders the <Selectors /> partial — the import was already at the top of the file but never rendered.
  • Reference page: selector row in the HostEndpointSpec table now points at #selectors.

2. policyrecommendation.tigera.io/status lifecycle was undocumented

The HEP page describes the user-controlled stagedAction lifecycle (Learn / Set / Ignore), and mentions stabilizationPeriod only as a config knob. The engine's own readiness signal — the policyrecommendation.tigera.io/status annotation moving through Learning → Stabilizing → Stable — wasn't documented anywhere. Users had no way to answer when is my recommendation ready to enforce?.

Verified against source: policy-recommendation/pkg/calico-resources/stagednetworkpolicy.go:53-57 and pkg/engine/recommendation.go:493-534.

Changes:

  • HEP page: new ### Track recommendation readiness section with the status table, the exact transition conditions (> 2 × interval, > stabilizationPeriod), the reset-on-modify behavior, two kubectl one-liners (single + bulk) for reading the annotation, and a tip to wait for Stable before accepting/enforcing.
  • Reference page: new ## Annotations on generated recommendations section documenting the full policyrecommendation.tigera.io/* annotation family (status, lastUpdated, scope, name, namespace), plus a ### Recommendation status lifecycle subsection 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 of globalnetworkpolicy.mdx. Leaving for a follow-up so this PR stays focused on EV-6623.

SME review

Merge checklist

  • Deploy preview inspected
  • Local build passes (BUILD_NEXT=true yarn build produced no new broken-link errors against the two changed pages)
  • Test have passed

…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.
Copilot AI review requested due to automatic review settings May 20, 2026 08:20
@netlify
Copy link
Copy Markdown

netlify Bot commented May 20, 2026

Deploy Preview for calico-docs-preview-next ready!

Name Link
🔨 Latest commit 9bd8981
🔍 Latest deploy log https://app.netlify.com/projects/calico-docs-preview-next/deploys/6a0d7cd685fe63000804e139
😎 Deploy Preview https://deploy-preview-2734--calico-docs-preview-next.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 20, 2026

Deploy Preview succeeded!

Built without sensitive environment variables

Name Link
🔨 Latest commit 9bd8981
🔍 Latest deploy log https://app.netlify.com/projects/tigera/deploys/6a0d7cd6bab6e00008ead0f2
😎 Deploy Preview https://deploy-preview-2734--tigera.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 74 (🔴 down 14 from production)
Accessibility: 98 (no change from production)
Best Practices: 92 (🟢 up 9 from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 namespaceSpec and hostEndpointSpec, but only the HostEndpointSpec table’s selector row links readers to #selectors. To avoid leaving the namespace selector without operator syntax guidance, either add the same #selectors reference to the NamespaceSpec selector row 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.

Comment on lines +74 to +102
| 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. |
Copy link
Copy Markdown
Collaborator

@ctauchen ctauchen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some suggestions for you, thanks for this!

@electricjesus


### Scope recommendations to specific hosts

By default, every HostEndpoint in the cluster is eligible for
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
By default, every HostEndpoint in the cluster is eligible for
By default, every host endpoint in the cluster is eligible for

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps "matches the labels of the host endpoint you want to cover."

"spec": {
"hostEndpointSpec": {
"recommendationStatus": "Enabled",
"selector": "environment == '\''prod'\''"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Comment on lines +327 to +328
global network policy. Use it to know when a recommendation has settled
down enough to enforce.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mid-Stabilizing

during a Stabilizing period, perhaps?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
@ctauchen
Copy link
Copy Markdown
Collaborator

LGTM for me. Need other approvals or ready to merge? @electricjesus

@electricjesus
Copy link
Copy Markdown
Member Author

Thanks @ctauchen! I will wait for @xiumozhan to confirm first

@electricjesus electricjesus marked this pull request as ready for review May 20, 2026 11:05
@electricjesus electricjesus requested a review from a team as a code owner May 20, 2026 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants