Skip to content

ci(config): enforce lowerCamelCase and max depth in reference.conf#30

Open
bladehan1 wants to merge 1 commit into
developfrom
ci/reference-conf-gate
Open

ci(config): enforce lowerCamelCase and max depth in reference.conf#30
bladehan1 wants to merge 1 commit into
developfrom
ci/reference-conf-gate

Conversation

@bladehan1
Copy link
Copy Markdown
Owner

@bladehan1 bladehan1 commented May 20, 2026

What does this PR do?

Adds a CI gate that scans common/src/main/resources/reference.conf and fails the build when any key violates either of:

  1. Every named path segment matches ^[a-z][a-zA-Z0-9]*$ (lowerCamelCase — required by ConfigBeanFactory auto-binding).
  2. Total path depth is <= 6. Each list/array step counts as one additional level — e.g. rate.limiter.rpc[].component is depth 5 (rate=1, limiter=2, rpc=3, []=4, component=5).

Implementation:

  • .github/scripts/check_reference_conf.py — parses via pyhocon, the reference Python HOCON implementation. Returns a fully-merged ConfigTree where dotted-form keys expand into nested objects — the same canonical key set Typesafe Config / ConfigBeanFactory see at runtime. Handles triple-strings, substitutions, includes, +=, block comments, etc. without us re-implementing the grammar.
  • Walker recurses into object elements of arrays so inner fields (e.g. each entry in rate.limiter.rpc = [{ component=..., ... }]) are validated the same way. Element keys are deduplicated across list entries because well-formed arrays use homogeneous object shapes.
  • Violation checks apply only to leaf keys — a single user-declared deep key produces exactly one report (not once per intermediate node along the way).
  • Integrated as a Validate reference.conf key names and depth step in the existing checkstyle job of .github/workflows/pr-check.yml — saves runner-minutes vs a standalone workflow.
  • On violation: emits one consolidated GHA annotation (::error file=...) with all entries packed via %0A so they show in the Checks panel; sys.exit(1) is the sole failure driver (no exit 1 in the workflow shell wrapper).
  • --debug flag prints every parsed key with its depth in walk order; trailing / marks namespace intermediates. Useful for manual verification against the source file.

Why are these changes required?

Without an automated gate, key names in reference.conf have drifted: 4 legacy keys (node.http.PBFTEnable, node.http.PBFTPort, node.rpc.PBFTEnable, node.rpc.PBFTPort) start with an uppercase acronym and require manual normalization in Args.java. Each additional drift costs reviewer attention and risks silent ConfigBeanFactory binding failures.

The 4 existing violators are grandfathered via an explicit ALLOWLIST so the gate fails only on new violations.

This PR has been tested by:

  • Unit Tests — local dry-run on common/src/main/resources/reference.conf returns OK: ... 294 keys, all lowerCamelCase, depth <= 6 (exit 0). The 294 includes 13 array-element fields under genesis.block.assets[], genesis.block.witnesses[], and event.subscribe.topics[].
  • Manual Testing — injected probes on a throw-away file: a bad-cased key, a name with an underscore, a name starting with a digit, and a 7-level nested chain (one over the limit). The gate failed with one report line per declaration and a consolidated ::error annotation; reverting passes again.
  • --debug output manually eyeballed against the source file; depth column shows the [] array steps explicitly so MAX_DEPTH math is verifiable by inspection.

Follow up

  • Out of scope here, but could be tackled later: renaming the 4 PBFT keys (requires a compatibility shim in Args.java since user config.conf files use the legacy names).
  • A separate gate to confirm bean-field ↔ key parity (each new key has a matching XxxConfig.java field) — deliberately not coupled with this PR.

Extra details

  • MAX_DEPTH = 6 (current max is 5, one level of headroom).
  • KEY_REGEX = ^[a-z][a-zA-Z0-9]*$; allowlist contains exactly the 4 PBFT keys.
  • pBFTExpireNum, allowPBFT, isOpenFullTcpDisconnect start with lowercase and pass the regex unchanged.
  • Commented-out examples in reference.conf (e.g. node.shutdown.BlockTime) are not seen by pyhocon, so they don't need to be allowlisted.

Summary by cubic

Adds a CI gate to enforce lowerCamelCase and a max depth of 6 for reference.conf keys, including keys inside arrays. Parses with pyhocon to match runtime binding, emits one consolidated ::error on violations, allowlists four legacy PBFT* keys, and supports --debug to print parsed keys and depths.

  • New Features
    • Runs .github/scripts/check_reference_conf.py in the checkstyle job.
    • Installs Python 3.11 and pyhocon in .github/workflows/pr-check.yml.

Written for commit cd96b77. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • Chores
    • Added a new CLI configuration validator that inspects configuration keys for naming and nesting depth, offers a debug mode to inspect parsed keys, prints grouped violation summaries, and exits non‑zero on failures.
    • Integrated the validator into CI so violations produce a consolidated error annotation and fail the check to prevent regressions.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

Adds a Python CLI .github/scripts/check_reference_conf.py that parses reference.conf (via pyhocon), walks all dotted keys to enforce lowerCamelCase segments and a maximum key depth (with an allowlist), reports violations (with a consolidated GitHub Actions ::error), and wires the check into the checkstyle CI job.

Changes

Reference Configuration Validation

Layer / File(s) Summary
Module docstring, imports and rules
.github/scripts/check_reference_conf.py
Adds module header/usage, checks for pyhocon, and defines MAX_DEPTH, KEY_REGEX, and ALLOWLIST.
ConfigTree traversal (walk)
.github/scripts/check_reference_conf.py
Adds walk(node, path, depth) to traverse ConfigTree and lists, treating arrays as synthetic [] depth steps and deduplicating homogeneous entries while yielding dotted paths and leaf/namespace metadata.
Main CLI parsing, debug, and parse step
.github/scripts/check_reference_conf.py
Implements main(argv) argument parsing (including --debug), validates input path, parses the file via ConfigFactory.parse_file, and optionally prints walked key list with depth and leaf/namespace markers.
Validation, reporting, and CI annotations
.github/scripts/check_reference_conf.py
Filters leaves, computes per-segment format violations (applying ALLOWLIST) and depth violations, prints grouped summaries, emits one consolidated GitHub Actions ::error annotation for offending entries or parse errors, and returns exit codes 0/1/2.
Success path, entrypoint, and CI integration
.github/scripts/check_reference_conf.py, .github/workflows/pr-check.yml
Prints OK with total key count on success and returns 0; adds if __name__ == "__main__": sys.exit(main(sys.argv)); updates the checkstyle job to install Python 3.11, install pyhocon, and run the validator against common/src/main/resources/reference.conf before JDK setup.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through keys both deep and wide,
Checking camel segments with careful pride,
If nesting climbs beyond our cap, I cry—
A CI bell rings and the errors fly,
Back to the burrow to tidy each line.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding CI enforcement of lowerCamelCase naming and max depth validation in reference.conf.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/reference-conf-gate

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/scripts/check_reference_conf.py:
- Around line 108-117: The parser only pushes the key prefix into frames when
the delimiter is a literal '{', so cases like "foo = {", "foo: {", or "foo = [ {
... } ]" lose the "foo" prefix; update the branch in the block around ident
handling (the code that checks p2 < n and src[p2] in '=:{') to treat a following
'{' or '[' as a nested-value indicator regardless of whether the delimiter was
'=' or ':' and push the full_parts prefix onto frames; if src[p2] == '{' push
{"kind":"obj","prefix":full_parts}, if src[p2] == '[' push
{"kind":"arr","prefix":full_parts}, and set pos = p2 + 1 in both cases so nested
object/array keys retain the parent key prefix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ac43e6ed-37ff-4ccc-b11a-352a56d2c404

📥 Commits

Reviewing files that changed from the base of the PR and between 381d369 and ef5dd53.

📒 Files selected for processing (2)
  • .github/scripts/check_reference_conf.py
  • .github/workflows/pr-check.yml

Comment thread .github/scripts/check_reference_conf.py Outdated
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 2 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .github/scripts/check_reference_conf.py Outdated
Comment thread .github/scripts/check_reference_conf.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/pr-check.yml:
- Around line 106-113: Pin the GitHub action and the pyhocon install to
immutable versions: replace uses: actions/setup-python@v5 with the action
referenced by its full commit SHA (e.g., actions/setup-python@<commit-sha>) and
change the pip install step to install a specific pyhocon release (e.g., pip
install pyhocon==<version>), updating the workflow steps that currently
reference actions/setup-python@v5 and the pip install command so the action and
dependency are immutable and reproducible.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 423dc7fa-48b7-40eb-80e8-3482cc0ee539

📥 Commits

Reviewing files that changed from the base of the PR and between ef5dd53 and e7d540a.

📒 Files selected for processing (2)
  • .github/scripts/check_reference_conf.py
  • .github/workflows/pr-check.yml

Comment thread .github/workflows/pr-check.yml
@bladehan1 bladehan1 force-pushed the ci/reference-conf-gate branch from e7d540a to 52d2e77 Compare May 20, 2026 08:52
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/scripts/check_reference_conf.py:
- Line 54: The constant MAX_DEPTH is set one too high; change MAX_DEPTH from 6
to 5 to enforce the PR contract of <= 5 depth (update the variable MAX_DEPTH in
this script and any tests or references that assume the limit); ensure any
related comparisons or error messages referencing MAX_DEPTH still reflect the
new value.
- Around line 84-95: The walk function currently only increments and emits the
synthetic array step (array_path/array_depth) when list elements are ConfigTree,
so pure scalar lists never report the array step; modify the list branch in walk
(the variables node, array_path, array_depth, seen) to always emit the
array_path once for scalar elements: detect if the list contains any
non-ConfigTree scalars (or no ConfigTree yielded subpaths) and yield array_path
with array_depth and sub_leaf=True (or appropriate leaf flag) exactly once
before/if you skip into per-element traversal, and still keep the existing logic
for ConfigTree elements while using seen to avoid duplicate sub_path emissions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6b6d3ef0-c4ee-4a5f-b0ed-98edebc650b2

📥 Commits

Reviewing files that changed from the base of the PR and between e7d540a and 52d2e77.

📒 Files selected for processing (2)
  • .github/scripts/check_reference_conf.py
  • .github/workflows/pr-check.yml

Comment thread .github/scripts/check_reference_conf.py
Comment thread .github/scripts/check_reference_conf.py Outdated
@bladehan1 bladehan1 force-pushed the ci/reference-conf-gate branch from 52d2e77 to ff0474c Compare May 20, 2026 09:03
Comment thread .github/scripts/check_reference_conf.py
Comment thread .github/scripts/check_reference_conf.py
Comment thread .github/scripts/check_reference_conf.py
Comment thread .github/scripts/check_reference_conf.py Outdated
Comment thread .github/scripts/check_reference_conf.py
Comment thread .github/scripts/check_reference_conf.py
@bladehan1 bladehan1 force-pushed the ci/reference-conf-gate branch from ff0474c to ef37233 Compare May 20, 2026 10:26
Add a CI gate that scans common/src/main/resources/reference.conf and
fails the build when any key violates lowerCamelCase
(^[a-z][a-zA-Z0-9]*$ per dot-separated segment) or exceeds the maximum
hierarchy depth (6). Array element keys are validated the same way;
each array step counts as one depth level — e.g. an inner field at
`rate.limiter.rpc[].component` is depth 5.

Parsing is delegated to pyhocon, the reference Python HOCON
implementation. It returns a fully-merged ConfigTree where dotted-form
keys expand into nested objects — the same canonical key set Typesafe
Config and ConfigBeanFactory see at runtime — and handles
triple-strings, substitutions, includes, +=, and block comments
without us re-implementing the grammar.

Four legacy PBFT* keys are grandfathered via an in-script allowlist
so the gate fails only on new violations. A consolidated GHA error
annotation lists every offending key, and sys.exit(1) drives step
failure. The script also accepts `--debug` to print every parsed key
with its depth (trailing `/` marks namespace intermediates) for
manual verification against the source file.

Runs as a new step in the existing checkstyle job of pr-check.yml
(setup-python + `pip install pyhocon`), so no extra runner spin-up.
@bladehan1 bladehan1 force-pushed the ci/reference-conf-gate branch from ef37233 to cd96b77 Compare May 20, 2026 10:37
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.

1 participant