Skip to content

Commit 749ba65

Browse files
authored
Fix property extractor incorrectly reading runtime (#155)
mutability as default Property extractor was reading the runtime mutability flag (first param after *this) instead of the actual default value. This caused incorrect defaults like enable_shadow_linking showing true instead of false. Fixed by using backward search to find the last non-validator parameter. Verified against source: 54/54 tests passing, 100% accuracy on real data.
1 parent 319ee02 commit 749ba65

File tree

3 files changed

+51
-24
lines changed

3 files changed

+51
-24
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@redpanda-data/docs-extensions-and-macros",
3-
"version": "4.12.3",
3+
"version": "4.12.4",
44
"description": "Antora extensions and macros developed for Redpanda documentation.",
55
"keywords": [
66
"antora",

tools/property-extractor/transformers.py

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -80,24 +80,45 @@
8080
based on feature requirements. Understanding these "arities" (parameter counts) is crucial
8181
for correctly extracting property metadata.
8282
83+
┌─────────────────────────────────────────────────────────────────────────────
84+
│ ALL properties have a runtime mutability flag as their FIRST parameter
85+
│ (after *this which is skipped by the parser). This boolean indicates whether
86+
│ the property can be changed at runtime without restarting Redpanda.
87+
88+
│ C++ signature: property<T>(*this, runtime_mutable, name, description, ...)
89+
│ After parsing: params[0] = runtime_mutable, params[1] = name, ...
90+
│ params[-1] = default OR validator (validator is skipped)
91+
92+
│ Note: Some properties include validators as the last parameter. These are
93+
│ automatically detected and skipped when extracting the default value.
94+
│ The default is the last NON-VALIDATOR parameter.
95+
└─────────────────────────────────────────────────────────────────────────────
96+
8397
BASIC PROPERTY PATTERNS:
8498
┌─────────────────────────────────────────────────────────────────────────────
85-
2-PARAMETER: property<T>(name, description)
86-
│ Example: property<bool>(*this, "enable_feature", "Enable the feature")
99+
3-PARAMETER: property<T>(runtime_mutable, name, description)
100+
│ Example: property<bool>(*this, true, "enable_feature", "Enable the feature")
87101
│ Used for: Simple properties with no metadata or custom defaults
88-
│ Extraction: [0] = name, [1] = description
102+
│ Extraction: [0] = runtime_mutable, [1] = name, [2] = description
89103
└─────────────────────────────────────────────────────────────────────────────
90104
┌─────────────────────────────────────────────────────────────────────────────
91-
3-PARAMETER: property<T>(name, description, default)
92-
│ Example: property<int>(*this, "port", "Server port", 9092)
105+
4-PARAMETER: property<T>(runtime_mutable, name, description, default)
106+
│ Example: property<int>(*this, false, "port", "Server port", 9092)
93107
│ Used for: Properties with simple custom default values
94-
│ Extraction: [0] = name, [1] = description, [2] = default
108+
│ Extraction: [0] = runtime_mutable, [1] = name, [2] = description, [3] = default
95109
└─────────────────────────────────────────────────────────────────────────────
96110
┌─────────────────────────────────────────────────────────────────────────────
97-
4-PARAMETER: property<T>(name, description, meta, default)
98-
│ Example: property<bool>(*this, "flag", "Description", meta{.needs_restart=yes}, true)
111+
5-PARAMETER: property<T>(runtime_mutable, name, description, meta, default)
112+
│ Example: property<bool>(*this, true, "flag", "Desc", meta{.needs_restart=yes}, true)
99113
│ Used for: Properties with metadata (restart requirements, visibility, etc.)
100-
│ Extraction: [0] = name, [1] = description, [2] = meta{}, [3] = default
114+
│ Extraction: [0] = runtime_mutable, [1] = name, [2] = description, [3] = meta{}, [4] = default
115+
└─────────────────────────────────────────────────────────────────────────────
116+
┌─────────────────────────────────────────────────────────────────────────────
117+
│ WITH VALIDATOR: property<T>(runtime_mutable, name, description, [meta], default, validator)
118+
│ Example: property<int>(*this, true, "port", "Port", 9092, [](int v){return v > 0;})
119+
│ Used for: Properties with runtime validation functions
120+
│ Extraction: Validator is automatically skipped; default is found by searching backwards
121+
│ Note: Validators detected by is_validator_param() and excluded from default extraction
101122
└─────────────────────────────────────────────────────────────────────────────
102123
103124
ENTERPRISE PROPERTY PATTERNS (More Complex):
@@ -1391,31 +1412,37 @@ def parse(self, property, info, file_pair):
13911412
return property
13921413

13931414
# Find where the meta{} param is
1415+
# MetaParamTransformer converts meta strings to dicts with "type": "initializer_list"
13941416
meta_index = next(
13951417
(i for i, p in enumerate(params)
13961418
if isinstance(p.get("value"), (dict, str))
13971419
and ("meta{" in str(p["value"]) or
1398-
(isinstance(p["value"], dict) and "needs_restart" in p["value"]))),
1399-
None,
1420+
(isinstance(p["value"], dict) and p["value"].get("type") == "initializer_list"))
1421+
),
1422+
None
14001423
)
14011424

1402-
# Default comes immediately after meta
1403-
if meta_index is None:
1404-
default_index = 3 if len(params) > 3 else None
1405-
else:
1406-
default_index = meta_index + 1 if len(params) > meta_index + 1 else None
1425+
# The default value is the LAST NON-VALIDATOR parameter in the constructor
1426+
# Property structure: (*this, runtime_mutability_flag, name, description, [meta], default, [validator])
1427+
# After *this is skipped: [0]=runtime_flag, [1]=name, [2]=desc, [3]=meta?, [4]=default, [5]=validator?
1428+
# We need to search backwards to find the last parameter that's not a validator
1429+
if len(params) < 2:
1430+
return property
14071431

1408-
if default_index is None or default_index >= len(params):
1432+
# Search backwards for the last non-validator parameter
1433+
default_index = None
1434+
for i in range(len(params) - 1, -1, -1):
1435+
if not is_validator_param(params[i]):
1436+
default_index = i
1437+
break
1438+
1439+
if default_index is None:
14091440
return property
14101441

14111442
# Candidate default param
14121443
default_param = params[default_index]
14131444
default = default_param.get("value")
14141445

1415-
# Skip obvious validator params
1416-
if is_validator_param(default_param):
1417-
return property
1418-
14191446
# std::nullopt means "no default"
14201447
if isinstance(default, str) and "std::nullopt" in default:
14211448
property["default"] = None

0 commit comments

Comments
 (0)