@redpanda-data/docs-extensions-and-macros 5.11.1 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,6 +29,12 @@ const semver = require('semver')
29
29
  * overwritten.
30
30
  */
31
31
 
32
+ // Components known to publish Redpanda property data. Any other component that
33
+ // ships a redpanda-properties-<tag>.json attachment is picked up too: the docs
34
+ // UI resolves the tooltip dataset against the page's own component when that
35
+ // component declares available-properties-tag, so a component publishing its
36
+ // own data must get the attribute or its tooltips fall back to streaming's and
37
+ // describe different properties from the ones its pages document.
32
38
  const PROPERTIES_COMPONENTS = ['ROOT', 'streaming']
33
39
  const CONNECT_COMPONENTS = ['connect', 'redpanda-connect']
34
40
 
@@ -41,7 +47,9 @@ module.exports.register = function () {
41
47
 
42
48
  this.once('contentClassified', ({ contentCatalog }) => {
43
49
  contentCatalog.getComponents().forEach((component) => {
44
- const isProperties = PROPERTIES_COMPONENTS.includes(component.name)
50
+ const publishesProperties = (contentCatalog.findBy({ component: component.name, family: 'attachment' }) || [])
51
+ .some((file) => file.src.module === 'reference' && PROPERTIES_JSON_RX.test(file.src.relative.split('/').pop()))
52
+ const isProperties = PROPERTIES_COMPONENTS.includes(component.name) || publishesProperties
45
53
  const isConnect = CONNECT_COMPONENTS.includes(component.name)
46
54
  if (!isProperties && !isConnect) return
47
55
 
@@ -0,0 +1,188 @@
1
+ = Documenting properties and enterprise features before they ship
2
+ :toc:
3
+ :toclevels: 3
4
+
5
+ How to reference a configuration property or an enterprise feature that is not in a released version of Redpanda yet, so that the build checks your work instead of you having to remember which release something landed in.
6
+
7
+ For how the macros work generally, see link:PROPERTY_AND_ENTERPRISE_REFERENCES.adoc[the explainer] and link:REFERENCE.adoc[the macros reference].
8
+
9
+ == The two situations
10
+
11
+ Redpanda cuts release candidates before every release, and the docs track them on a prerelease branch (`beta`) that publishes under `/beta/` on the site. Two different things can be true of a feature or property on that branch:
12
+
13
+ *Unreleased.* It exists only in a release candidate. Nobody outside can get it yet. You are writing the docs ahead of the release so they ship with it.
14
+
15
+ *Released beta.* It is publicly available, but as a beta: real users can turn it on, and it may still change.
16
+
17
+ The distinction matters because it decides where a mention is allowed. An unreleased thing referenced from released docs promises readers something they cannot have. A released beta is fine to mention anywhere, as long as readers can see it is a beta.
18
+
19
+ The macros enforce that distinction, so the rule you need to remember is short: *write the mention on the branch the feature is actually on, and let the build tell you if you got it wrong.*
20
+
21
+ == Properties in a release candidate
22
+
23
+ === What has to exist first
24
+
25
+ A property mention is only as good as the property data behind it. Each release series publishes its own `redpanda-properties-v<major>.<minor>.<patch>.json` as a reference-module attachment, and a page validates against the file for *its own* series. A prerelease branch is no exception: it needs a file generated from the RC tag.
26
+
27
+ [,bash]
28
+ ----
29
+ # On the beta branch, from the docs repo
30
+ npx doc-tools generate property-docs --tag v26.3.1-rc1
31
+ ----
32
+
33
+ `--tag` accepts release-candidate tags. The generated file is `redpanda-properties-v26.3.1-rc1.json`, and because its series is `26.3` it is picked up by a component version at `version: 26.3`.
34
+
35
+ Regenerate it for each RC. Tags compare by release precedence, so `rc2` supersedes `rc1` and the GA `v26.3.1` supersedes both -- you can leave older RC files in place and the build will use the newest.
36
+
37
+ === Writing the mention
38
+
39
+ Once that file is committed on the branch, nothing special is needed. Write the macro as you would anywhere:
40
+
41
+ [,asciidoc]
42
+ ----
43
+ Set prop:my_new_property[] to enable the thing.
44
+ ----
45
+
46
+ The build validates the name against the RC data. A typo gets a warning naming the file it checked. A property that only exists in the RC validates on the beta branch and, correctly, fails validation if someone copies the sentence to a released branch, because it is not in that release's data.
47
+
48
+ === If you forget the property data
49
+
50
+ You get told, once per component version, with the command to run:
51
+
52
+ [literal]
53
+ ----
54
+ prop macro: streaming@26.3 publishes no redpanda-properties-v26.3.*.json attachment
55
+ in its reference module (found for other series: v26.2.1). prop: targets on 26.3
56
+ pages are therefore not validated and their tooltips carry no data, rather than
57
+ being checked against another release's properties. Generate it with
58
+ 'npx doc-tools generate property-docs --tag v26.3.<patch>' on that branch, or
59
+ leave prop: out of 26.3 content.
60
+ ----
61
+
62
+ Mentions render as plain code with no tooltip until the file exists. That is deliberate: validating 26.3 content against 26.2 data would accept properties that release never had and flag removed ones as typos.
63
+
64
+ === Cloud pages and release candidates
65
+
66
+ Cloud runs released Redpanda, so Cloud pages always validate against the newest *GA* property data and ignore release candidates entirely. You cannot document an RC-only property on a Cloud page, and you should not want to -- the property is not in Cloud until the release ships and Cloud picks it up.
67
+
68
+ A property is available to Cloud only when its `cloud_supported` field is `true`, which comes from the Cloud support data the extractor fetches. For a property new in an RC that flag is `false`, so a Cloud mention renders as plain code with a warning. When Cloud gains the property, regenerating the data flips the flag and the mention starts working with no docs change.
69
+
70
+ === Single-sourced pages need a second look
71
+
72
+ A Cloud page that is a stub including a self-managed page inherits that page's `prop:` calls, and they are then checked against Cloud's surface. A self-managed-only property therefore renders as plain code on the Cloud rendering of shared prose, with a warning naming the Cloud page even though the mention lives in the included file.
73
+
74
+ That is the macro doing its job: the shared sentence is telling a Cloud reader to set something they cannot set. Fix the prose rather than the macro -- usually by moving the instruction inside an `ifndef::env-cloud[]` block.
75
+
76
+ == Enterprise features in a release candidate
77
+
78
+ Enterprise features are declared in the registry (`enterprise-features.yml` in the `shared` component), and the release status lives there rather than in each mention. That way one edit updates every reference and every generated licensing table.
79
+
80
+ === Declaring the status
81
+
82
+ [,yaml]
83
+ ----
84
+ # Only in a release candidate: not public yet.
85
+ - name: My Upcoming Feature
86
+ scope: redpanda
87
+ status: unreleased
88
+ description: What it does.
89
+ expiration: What happens when the licence expires.
90
+
91
+ # Publicly available as a beta.
92
+ - name: My Beta Feature
93
+ scope: redpanda
94
+ status: beta
95
+ description: What it does.
96
+ expiration: What happens when the licence expires.
97
+ ----
98
+
99
+ `status` is one of:
100
+
101
+ [cols="1,3a"]
102
+ |===
103
+ | Value | Meaning
104
+
105
+ | `ga`
106
+ | Shipped. The default when `status` is absent, so existing entries need no change. Referenced anywhere, no badge.
107
+
108
+ | `beta`
109
+ | Publicly available as a beta. Referenced anywhere. Renders a `beta` badge in prose and in the licensing tables.
110
+
111
+ | `unreleased`
112
+ | In a release candidate only. Referenced *only* from prerelease docs. Renders an `unreleased` badge there, and is omitted from licensing tables on released docs.
113
+ |===
114
+
115
+ `beta: true` is the older spelling and still means `status: beta`. Prefer `status` in new entries: it can express "not public at all", which a boolean cannot.
116
+
117
+ Add `status-tooltip` to override the hover text on an `unreleased` badge, or `beta-tooltip` on a `beta` badge.
118
+
119
+ === Writing the mention
120
+
121
+ Unchanged:
122
+
123
+ [,asciidoc]
124
+ ----
125
+ enterprise:My Upcoming Feature[] requires a licence.
126
+ ----
127
+
128
+ On the prerelease branch this renders with the `unreleased` badge. On released docs it renders as plain text with no enterprise styling, no tooltip, and no link, plus a warning:
129
+
130
+ [literal]
131
+ ----
132
+ enterprise:My Upcoming Feature[] in modules/manage/pages/example.adoc:
133
+ 'My Upcoming Feature' is marked status: unreleased in the enterprise features
134
+ registry, so it is only documented for an upcoming release. This page belongs to
135
+ a released version, so the mention renders as plain text with no enterprise
136
+ styling, tooltip, or link. Move the mention to the prerelease (beta) branch, or
137
+ change the status once the feature ships.
138
+ ----
139
+
140
+ The `unreleased` badge cannot be suppressed with `enterprise-beta-badge=false`. "Not in a release yet" is information a reader needs, not decoration.
141
+
142
+ === Licensing tables
143
+
144
+ `enterprise_features::<scope>[]` omits `unreleased` features on released docs, because the table states what a licence covers today and listing something unavailable makes it wrong. On prerelease docs the same table lists them with their badge.
145
+
146
+ == When the release ships
147
+
148
+ Two edits, in this order:
149
+
150
+ . *Properties.* Generate the GA property data on the branch that becomes the released version:
151
+ +
152
+ [,bash]
153
+ ----
154
+ npx doc-tools generate property-docs --tag v26.3.1
155
+ ----
156
+ +
157
+ The GA tag supersedes its release candidates automatically, so no mention changes. Cloud starts seeing the new properties when the Cloud support data marks them `cloud_supported`.
158
+
159
+ . *Enterprise features.* Change `status: unreleased` to `status: beta` (if it ships as a public beta) or remove the `status` field (if it ships generally). Every mention and every table updates from that one edit.
160
+
161
+ Nothing in prose needs touching for either.
162
+
163
+ == Checklist
164
+
165
+ Before opening a PR that documents something unreleased:
166
+
167
+ * [ ] The mention is on the prerelease branch, not on `main` or a released `v/*` branch.
168
+ * [ ] For a property: the RC property JSON is committed on that branch, generated from the RC tag.
169
+ * [ ] For an enterprise feature: the registry entry has `status: unreleased`, not `beta: true`, unless it is genuinely a public beta.
170
+ * [ ] The build log has no `prop macro:` or `enterprise:` warnings for your additions.
171
+ * [ ] No mention of an unreleased property or feature on a Cloud page.
172
+
173
+ == Seeing it work
174
+
175
+ The preview site in this repository has fixtures for every case above, including a prerelease component version and a Cloud component:
176
+
177
+ [,bash]
178
+ ----
179
+ ./scripts/macro-test.sh --serve
180
+ ----
181
+
182
+ Open `/preview/macros-showcase/`, which shows each macro call, what it renders, and why. `/preview/release-status-test/` and `/macro-fixtures/26.3/` show the same unreleased feature gated on a released version and badged on a prerelease one.
183
+
184
+ == Why the build enforces this rather than trusting reviewers
185
+
186
+ Every one of these rules is checkable from data the build already has: which release series a page belongs to, whether its component version is a prerelease, which properties that release actually defines, and what the registry says about a feature's status. A reviewer would have to hold all of that in their head across hundreds of mentions and nine doc versions.
187
+
188
+ So the macros check it, and the failure mode is always the same: render the plain name and say why. That is deliberate. A wrong tooltip or a link to a page describing a feature nobody can get is worse than no tooltip at all, because the reader has no way to tell it is wrong.
@@ -23,7 +23,9 @@ prop:cloud_storage_enabled[]
23
23
 
24
24
  That's it. Here's what happens for you:
25
25
 
26
- *It's checked.* The name is looked up in the published property data -- the same JSON, generated from Redpanda's source code, that powers the reference pages and tooltips. A typo gets a build warning with the file name and a "did you mean" suggestion. Nothing unverified ships. (A site can turn this up to a hard build failure with the `property-validate` attribute.)
26
+ *It's checked, against the right release.* The name is looked up in the published property data -- the same JSON, generated from Redpanda's source code, that powers the reference pages and tooltips. A typo gets a build warning naming the file, the release data it was checked against, and a "did you mean" suggestion. Nothing unverified ships. (A site can turn this up to a hard build failure with the `property-validate` attribute.)
27
+
28
+ Every release series has its own copy of that data, and the build picks the copy matching the page's own version: a 25.3 page is checked against 25.3 properties, never against the newest. Otherwise a property added in 26.2 would pass silently on a 25.3 page, and one removed since 25.3 would be flagged there as a typo. If a version branch has no property data of its own, the build says so and skips validation for that version rather than substituting a neighbouring release's -- and names the command that generates the missing file.
27
29
 
28
30
  *It gets a tooltip.* The docs UI decorates only elements the macro marked. A plain backticked word never gets a tooltip anymore, so `admin` in a Helm example stays plain text unless a writer deliberately writes `prop:admin[]`.
29
31
 
@@ -37,10 +39,26 @@ That's it. Here's what happens for you:
37
39
 
38
40
  Rather than hardcoding "cluster properties live on the cluster-properties page," the macro reads the actual docs during the build. Every documented property appears as a heading in the generated property files, and each reference page pulls in one or more of those files. The macro follows that chain -- which pages exist, what they include, which property headings end up where -- and builds a lookup table per doc set.
39
41
 
40
- Because the lookup is done separately for each part of the site, a Cloud page links to Cloud's own property pages and a streaming page to streaming's. Cloud reuses streaming's property files with a filter ("only the cloud-relevant parts"), and the macro applies that same filter, so it never links to a property that a given page doesn't actually document. If a doc set doesn't cover a property at all -- Cloud publishes no topic-properties page, Connect publishes none -- the link borrows the streaming docs instead of pointing nowhere.
42
+ Because the lookup is done separately for each part of the site, a Cloud page links to Cloud's own property pages and a streaming page to streaming's, and a link is only ever emitted when a page in that same doc set actually documents the property. Nothing is linked across doc sets, and no page is guessed from a property's scope -- a link the build can't verify is a broken link.
43
+
44
+ Availability is a separate question from linking, and it comes from the data rather than from which pages happen to include what. The published JSON marks each property with `cloud_supported`. Cloud is managed Redpanda, so a Cloud page may reference only the properties that flag covers, and it always reads the newest self-managed file: there is no such thing as a Cloud release of the property list. A property Cloud doesn't support renders as plain code in code font -- no link and no tooltip -- plus a build warning naming the property and the file. A tooltip there would tell a Cloud reader they can change something they can't. (`cloud_supported` is the whole gate: no published property is editable or read-only in Cloud without also being supported.)
45
+
46
+ Usefully, the current data has no Cloud-supported *topic* property at all -- all 62 are cluster properties. So a topic property mentioned on a Cloud page isn't a missing page; it genuinely doesn't apply.
47
+
48
+ Doc sets with no property data -- Connect, the agentic data plane -- get nothing, and nothing is inferred for them. Their version numbers are their own product's, and say nothing about which Redpanda properties exist. Adding a third doc set is a deliberate change to the macro, not something it guesses.
49
+
50
+ An available property that no page *renders* is a different situation, and keeps its tooltip. Deprecated properties are the usual case: the reference pages filter them out, but the published data still describes them accurately, so a tooltip on the deprecated-properties page is exactly what a reader wants. There's no page to link, so `link=true` renders unlinked and warns; a tooltip-only mention is silent.
41
51
 
42
52
  Think phone book, not memory: if a property moves, the next build's phone book is already right.
43
53
 
54
+ === Features and properties that have not shipped yet
55
+
56
+ Redpanda cuts release candidates before every release, and the docs track them on a prerelease branch. Something in an RC is not the same as something in a public beta, and the difference decides where a mention is allowed: an unreleased thing referenced from released docs promises readers something they cannot have.
57
+
58
+ Both macros enforce that from data rather than from reviewer memory. A property validates against its own release series, so an RC-only property works on the beta branch and fails on a released one. An enterprise feature carries `status: unreleased` or `status: beta` in the registry, and an unreleased feature referenced from released docs renders as plain text with a warning, and is omitted from licensing tables there. Cloud always uses GA property data and ignores release candidates entirely, because Cloud runs released Redpanda.
59
+
60
+ The writer-facing procedure, including how to generate property data from an RC tag, is in link:DOCUMENTING_UNRELEASED_FEATURES.adoc[Documenting properties and enterprise features before they ship].
61
+
44
62
  === What happened to config_ref
45
63
 
46
64
  The old `config_ref` macro did a smaller version of this job with three problems: you had to tell it which page to link to by hand, it never checked the property name, and on Kubernetes pages it prefixed *every* property with `storage.tiered.config.` -- which is only correct for tiered storage settings. The live docs really did render `storage.tiered.config.log_segment_size`, a path that mislabels where that setting belongs.
@@ -113,6 +113,31 @@ Set to `false` to render the term without a link.
113
113
  enterprise-beta-badge::
114
114
  Set to `false` to suppress the beta badge in prose. Generated tables always show it. See <<beta-features>>.
115
115
 
116
+ [[release-status]]
117
+ === Release status
118
+
119
+ A registry entry's `status` field declares where a feature may be referenced. It is the enterprise equivalent of `cloud_supported` for properties: one field in the data, checked at build time, rather than a rule reviewers have to remember.
120
+
121
+ [cols="1,3a"]
122
+ |===
123
+ | `status` | Behavior
124
+
125
+ | `ga` (default)
126
+ | Shipped. Referenced anywhere, no badge. Applies when `status` is absent, so existing entries need no change.
127
+
128
+ | `beta`
129
+ | Publicly available as a beta. Referenced anywhere, with a `beta` badge in prose and in the generated tables.
130
+
131
+ | `unreleased`
132
+ | In a release candidate only, not public. Referenced *only* from a prerelease component version. On a released page the mention renders as plain text with no enterprise styling, tooltip, or link, and the build reports it according to `enterprise-validate`. Omitted from `enterprise_features` tables on released pages; listed with its badge on prerelease pages.
133
+ |===
134
+
135
+ A prerelease page is one whose component version sets `prerelease` in `antora.yml`. A playbook can declare it directly with the `page-component-version-is-prerelease` document attribute.
136
+
137
+ `beta: true` predates this field and still means `status: beta`, so old entries keep working. Prefer `status` in new entries, because a boolean cannot express "not public at all". An unrecognized `status` value is reported rather than silently treated as shipped. Use `status-tooltip` to override the `unreleased` badge's hover text.
138
+
139
+ For the writer-facing procedure, see link:DOCUMENTING_UNRELEASED_FEATURES.adoc[Documenting properties and enterprise features before they ship].
140
+
116
141
  [[beta-features]]
117
142
  === Beta features
118
143
 
@@ -186,7 +211,7 @@ Registered together with the `enterprise` inline macro (see <<enterprise>>).
186
211
 
187
212
  This inline macro references a Redpanda configuration property in prose. The property renders as a marked `<code>` element (`property-ref` class plus a `data-property-name` attribute) that the docs UI decorates with a hover-documentation tooltip. Marking is opt-in: only properties referenced through this macro get tooltips, so ambiguous words such as `admin` or `rack` in unrelated contexts (Helm values, feature settings) are never decorated by mistake.
188
213
 
189
- The macro validates its target against the published property reference: the newest `redpanda-properties-<tag>.json` attachment in the `reference` module of the build, the same data the tooltips fetch at runtime. To migrate existing plain-backtick property mentions, use `doc-tools generate migrate-property-refs`.
214
+ The macro checks that a property is actually available to the audience reading the page, and links it only where a page documents it. It validates against the published property data: a `redpanda-properties-<tag>.json` attachment in the `reference` module, the same data the tooltips fetch at runtime. See <<prop-availability>> for which properties each doc set may reference and <<prop-version-selection>> for which file a given page uses. To migrate existing plain-backtick property mentions, use `doc-tools generate migrate-property-refs`.
190
215
 
191
216
  === Usage
192
217
 
@@ -201,7 +226,7 @@ prop:write_caching_default[text=write caching]
201
226
  The macro target is the property name. Named attributes:
202
227
 
203
228
  link::
204
- Set to `true` to also link the property to its reference page. The page is discovered dynamically: the macro indexes which reference-module page in the current component documents each property, by scanning property headings in the partials each page includes (respecting include tag filters such as `tags=redpanda-cloud`). Links are component-relative, so a Cloud page links to the Cloud component's own property pages, and they keep working if properties are split across different pages in the future. When discovery finds nothing, the page falls back deterministically to the property's `config_scope` (`cluster`, `broker`, or `topic`). This supersedes the `config_ref` macro's linking for most uses.
229
+ Set to `true` to also link the property to its reference page. The page is discovered dynamically: the macro indexes which reference-module page in the current component documents each property, by scanning property headings in the partials each page includes (respecting include tag filters such as `tags=redpanda-cloud`). Links are component-relative, so a Cloud page links to the Cloud component's own property pages, and they keep working if properties are split across different pages in the future. See <<prop-undocumented>> for properties the current component does not document. This supersedes the `config_ref` macro's linking for most uses.
205
230
 
206
231
  page::
207
232
  Optional reference-page override (module-relative, without `.adoc`), for example `properties/object-storage-properties`. Overrides discovery entirely.
@@ -215,11 +240,75 @@ Optional display text override. Wins over the Helm path display.
215
240
  === Configuration options
216
241
 
217
242
  property-validate::
218
- How to report a target that does not match any published property: `warn` (default) logs a build warning with the file path and close-match suggestions, `error` fails the build, and `off` disables validation. When no property JSON is available in the build, the macro renders without validation and logs a single warning.
243
+ How to report a target that does not match any published property: `warn` (default) logs a build warning with the file path, the dataset the page was checked against, and close-match suggestions; `error` fails the build; and `off` disables validation and silences every warning described here. When no property JSON is available in the build, the macro renders without validation and logs one warning per component version.
244
+
245
+ [[prop-version-selection]]
246
+ === Which property data a page validates against
247
+
248
+ Each published Redpanda release series ships its own `redpanda-properties-v<major>.<minor>.<patch>.json`, so a page must be checked against the data for *its own* series. A 25.3 page validated against 26.2 data would accept properties that release never had and flag removed ones as typos.
249
+
250
+ The macro therefore selects by series (`major.minor`) rather than by newest tag:
251
+
252
+ . For a component version with a numeric series (`streaming` at `25.3`), the newest patch whose tag matches that series -- preferring the copy attached to the page's own version, then the same series published anywhere in the component, since a series' JSON sometimes lives only on the main branch. Patch numbers compare numerically, so `v25.3.11` beats `v25.3.2`.
253
+ . For a Cloud component (`env-cloud`), the newest `streaming` dataset, then `ROOT`. Cloud is managed Redpanda and always tracks the current release, so its own version is never consulted.
254
+
255
+ Selecting by series rather than newest tag matters in practice: the docs repo's main branch carries the previous series' JSON alongside its own, and a prerelease tag could land there too. Newest-tag-wins would hand that file to pages of a different release. A component with no property data and no `env-cloud` attribute gets no dataset at all -- see <<prop-availability>>.
256
+
257
+ Tags compare by release precedence, so a GA release outranks its own release candidates and `rc2` outranks `rc1`. A cycle publishes `v26.3.1-rc1`, then `rc2`, then the GA `v26.3.1`, and a beta branch at `version: 26.3` lands on the newest of those deterministically rather than on whichever file the content catalog happened to yield first. Redpanda spells prereleases as one identifier (`-rc2`, not `-rc.2`), which the semver spec compares as a string, so the trailing digits are split out before comparing; otherwise `rc10` would sort below `rc2`.
258
+
259
+ Cloud takes the newest *GA* dataset and ignores prereleases entirely, because Cloud runs released Redpanda. An RC published on a beta branch outranks the current GA by version number, so without this every Cloud page would start validating against an unreleased property list. When a build contains only prerelease data, Cloud goes unvalidated and the warning says so specifically rather than reporting no data at all.
260
+
261
+ When a component publishes property data for other series but none for the page's own, the macro declines to validate rather than use a neighbouring release's data. It logs one warning per component version naming the missing file, the tags it did find, and the `doc-tools generate property-docs --tag` command that produces it. `prop:` targets on those pages render unvalidated and their tooltips carry no data, so either generate the series' JSON on that branch or leave `prop:` out of that version's content.
219
262
 
220
263
  property-ref-role::
221
264
  CSS class applied to the code element. The default is `property-ref`.
222
265
 
266
+ [[prop-availability]]
267
+ === Which properties a doc set may reference
268
+
269
+ Property data exists for two doc sets.
270
+
271
+ *Self-managed (`streaming`)* publishes its own properties JSON per release, as a reference-module attachment. Every property in that release's file is available.
272
+
273
+ *Cloud* is managed Redpanda, so it has no property data of its own and always tracks the newest self-managed file. A Cloud component is recognized by its `env-cloud` attribute.
274
+
275
+ A *cluster* property is available to Cloud unless its `cloud_supported` field is explicitly `false`. That field is the union of the Cloud states -- no published property is `cloud_editable` or `cloud_readonly` without also being `cloud_supported` -- so it is the single gate for that scope.
276
+
277
+ *Topic and broker* properties are not gated by it. `cloud_supported` is derived from the Cloud control plane's install pack, whose two sections (`customer_managed_configs` and `readonly_cluster_config`) describe cluster configuration and contain nothing else: every entry resolves to a cluster property, and no topic property appears anywhere in the file. A `false` value on another scope therefore asserted something that source cannot know, while Cloud users set topic properties routinely through the Kafka API and Console and Cloud publishes a topic properties reference of its own. The property extractor no longer writes the field for other scopes, and the macro treats an absent value as "no opinion", so already-published datasets stay correct too.
278
+
279
+ Any other component (`connect`, the agentic data plane, a preview site) has no property data, and none is inferred for it. Those components carry their own product versions, which say nothing about which Redpanda properties exist, so a version number is never read as a Redpanda release. Supporting a further doc set is a deliberate addition to the macro.
280
+
281
+ When a property is not available to the page's audience -- a non-`cloud_supported` property on a Cloud page -- the macro renders it as plain `<code>`: no link, no `data-property-name` marker, and therefore no tooltip. A tooltip would imply the reader can set something they cannot. The build logs a warning naming the property, the file, and the dataset consulted. Fix `cloud_supported` in the property extractor if the data is wrong; otherwise reword the sentence and drop the macro.
282
+
283
+ When no dataset covers the component at all, the macro warns once per component version and renders every `prop:` target as plain code, rather than emitting tooltips it could not verify.
284
+
285
+ === Linking
286
+
287
+ `link=true` links the property to its reference page, but only when a page *in the same component* documents it. Nothing is linked across components, and no target is guessed from the property's `config_scope`: a link the build cannot verify is a broken link. An available property that no page renders -- a deprecated property, or one held back by include tags -- keeps its tooltip and renders unlinked; `link=true` warns in that case. Use `page=` to set a target explicitly for one mention.
288
+
289
+ [[prop-property-source]]
290
+ ==== Declaring which page is the reference
291
+
292
+ A reference page can declare the property collection it publishes:
293
+
294
+ [,asciidoc]
295
+ ----
296
+ = Cluster Configuration Properties
297
+ :page-property-source: cluster-properties
298
+ ----
299
+
300
+ Claims on a property are then ranked, highest first:
301
+
302
+ . A page that declares `page-property-source`.
303
+ . A property heading pulled in from a generated partial.
304
+ . A bare heading on a page that happens to match a property name.
305
+
306
+ The ranking exists because inference alone is ambiguous. Several real property names are ordinary words -- `admin`, `brokers`, `rack`, `retries`, `superusers` -- so any reference page titled or sectioned with one of those would otherwise claim the property from the page that documents it, and a page title generates no anchor, so both the link and the tooltip URL would point at nothing. Ranking also makes resolution independent of the order Antora aggregates content, which is stable for one checkout but carries no meaning.
307
+
308
+ Within a rank, the first page wins, ordered by path so the result is deterministic. When two *declared* pages claim the same property the build warns and names both: that is an authoring conflict rather than something to resolve quietly.
309
+
310
+ Declaring the attribute is optional. Existing pages keep working through inference, and the declaration is worth adding when a property could plausibly be claimed by more than one page in the component, or to state the intent explicitly rather than relying on the generated partials happening to win.
311
+
223
312
  === Registration
224
313
 
225
314
  [,yaml]
package/macros/badge.js CHANGED
@@ -20,7 +20,15 @@ function buildBadgeHtml ({ label, size, tooltip } = {}) {
20
20
  const className = `badge--${text.toLowerCase().replace(/\s+/g, '-')}`;
21
21
  const isLarge = size === 'large';
22
22
  const sizeClass = isLarge ? 'badge--large' : '';
23
- const tooltipAttr = tooltip ? ` data-tooltip="${tooltip}"` : '';
23
+ // Escape before interpolating: tooltips come from a registry field, and an
24
+ // unescaped quote terminates the attribute early, turning the rest of the
25
+ // text into stray attributes (including event handlers).
26
+ const escapeAttr = (value) => String(value)
27
+ .replace(/&/g, '&amp;')
28
+ .replace(/"/g, '&quot;')
29
+ .replace(/</g, '&lt;')
30
+ .replace(/>/g, '&gt;');
31
+ const tooltipAttr = tooltip ? ` data-tooltip="${escapeAttr(tooltip)}"` : '';
24
32
 
25
33
  // Add brackets if not large. The brackets matter beyond styling: they are
26
34
  // real text content, so the label survives an HTML-to-Markdown conversion as