Skip to content

feat(bazel): guard the nested-module inventory - #484

Merged
kristinapathak merged 2 commits into
mainfrom
feat/bazel-nested-module-guard
Jul 28, 2026
Merged

feat(bazel): guard the nested-module inventory#484
kristinapathak merged 2 commits into
mainfrom
feat/bazel-nested-module-guard

Conversation

@balajinvda

@balajinvda balajinvda commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Why

Phase 2 of docs/dev/bazel-consolidation.md (#445).

Consolidation only succeeds if the number of nested Bazel modules moves in one direction, and nothing in CI notices when it does not. A new service arriving with its own MODULE.bazel is invisible until someone counts by hand, and a service that finishes migrating leaves no trace that the backlog shrank. Both directions need to be enforced for the migration to be measurable rather than asserted.

What changed

  • tools/ci/nested-modules.txt classifies all 20 nested modules currently on main.
  • tools/ci/check-nested-modules enforces it both ways. An unlisted nested module fails, because that is precisely what consolidation exists to prevent. A ledger entry whose module no longer exists also fails, so a completed migration must prune its line and the backlog cannot overstate how much work remains.
  • tools/ci/test-check-nested-modules covers the behavior, including both failure modes.
  • Wired into build-test, not bazel.yml, so it does not trigger the full Bazel matrix.

The ledger keeps the plan's three categories instead of collapsing into a single allowlist, because only exception carries the exception contract. Merging them would make every outstanding migration read as an accepted exception.

Current state, which the check prints on every run:

Category Count
Awaiting migration 18
Vendored (cel.dev/expr) 1
Scaffolding (rules/oci-destinations) 1
Permanent exceptions 0

nvsnap is absent from the file entirely, which is what a finished migration looks like here — it moved to the root module in #471.

Customer Release Notes

Not customer visible.

Plan Summary

Not applicable.

Usage

tools/ci/check-nested-modules      # enforce, and print the remaining count
tools/ci/test-check-nested-modules # behavioral tests

Testing

Both scripts run in build-test. Beyond the unit tests, I verified the guard fails on the real tree in both directions rather than only passing today:

  • adding src/clis/nvcf-cli/MODULE.bazel is reported as unclassified, exit 1
  • removing src/invocation-plane-services/ratelimiter/MODULE.bazel is reported as a stale ledger entry, exit 1

Notes

The check prints the remaining count on every run, so the phase has a running scoreboard rather than a periodic manual audit. As services migrate, their lines leave the ledger and the count falls toward zero.

References

None

Related Merge Requests/Pull Requests

Plan: #445. Phase 5a (nvsnap) landed in #471.

Dependencies

None

Summary by CodeRabbit

  • CI Improvements

    • Added an automated CI guard to verify the repository’s nested Bazel module inventory stays complete and up to date.
    • CI now fails on missing or stale nested module entries and reports targeted guidance for resolution.
  • Documentation

    • Added a maintained inventory file defining the expected nested module list and exception categories.
  • Tests

    • Added a suite of scenarios that validates correct behavior for valid inventories, missing/unlisted modules, stale ledger entries, exceptions, and invalid or malformed inventory data.

Phase 2 of docs/dev/bazel-consolidation.md. Consolidation only converges
if the count of nested modules moves in one direction, and nothing today
notices when it does not: a new service arriving with its own
MODULE.bazel is invisible until someone counts by hand.

Add tools/ci/nested-modules.txt classifying all 20 nested modules on
main, and tools/ci/check-nested-modules to enforce it in both
directions. An unlisted nested module fails, because that is the thing
consolidation exists to stop. A ledger entry whose module no longer
exists also fails, so a completed migration must prune its line and the
backlog cannot overstate itself.

The ledger keeps the plan's three categories rather than collapsing to
one allowlist, because only `exception` carries the exception contract.
Merging them would make every outstanding migration read as an accepted
exception. Today that is 18 awaiting migration, 1 vendored
(cel.dev/expr), 1 scaffolding (rules/oci-destinations), and no permanent
exceptions. nvsnap is absent entirely, which is what a finished
migration looks like here.

The check also prints the remaining count, so the phase has a running
scoreboard instead of a periodic manual audit.

Verified it fails on the real tree in both directions, not just that it
passes today: adding a MODULE.bazel under src/clis/nvcf-cli is reported
as unclassified, and removing ratelimiter's is reported as a stale
entry.

Runs in build-test, not bazel.yml, so it does not trigger the full Bazel
matrix.

Co-authored-by: Balaji Ganesan <bganesan@nvidia.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@balajinvda
balajinvda requested a review from a team as a code owner July 27, 2026 22:58
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a Bash inventory ledger and reconciliation check for nested Bazel modules, behavioral coverage for ledger and mismatch cases, and a CI step that runs both scripts.

Changes

Nested Bazel module inventory

Layer / File(s) Summary
Nested module ledger
tools/ci/nested-modules.txt
Records nested MODULE.bazel paths classified as vendored, scaffolding, or ledger entries.
Inventory reconciliation
tools/ci/check-nested-modules
Parses the ledger, discovers nested modules, detects unlisted or stale entries, and reports classification counts.
Checker validation and CI integration
tools/ci/test-check-nested-modules, .github/workflows/build-test.yml
Tests successful inventories, mismatches, exceptions, parsing rules, invalid categories, missing ledgers, and runs the checks in CI.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant InventoryCheck
  participant Ledger
  participant Repository
  CI->>InventoryCheck: Run test and inventory checks
  InventoryCheck->>Ledger: Read classified module paths
  InventoryCheck->>Repository: Discover nested MODULE.bazel files
  InventoryCheck-->>CI: Return counts or mismatch errors
Loading

Possibly related PRs

  • NVIDIA/nvcf#471: Removes a nested MODULE.bazel module whose path would be validated by this inventory check.

Suggested reviewers: kristinapathak

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title is well-formed, but this is a CI/tooling change, so feat misstates the primary nature of the diff. Change it to ci(bazel): guard the nested-module inventory to match the workflow/tooling changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/bazel-nested-module-guard

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@tools/ci/check-nested-modules`:
- Around line 51-55: Update the read loop in check-nested-modules so every
non-comment row missing its required path exits with status 2 instead of being
silently skipped, including ledger and exception rows. Preserve
comment/blank-row handling, and add a behavioral test covering a root-only tree
with a malformed ledger row.
- Around line 65-68: Update the validation flow in check-nested-modules before
calculating metrics to detect duplicate entries within each category and paths
classified under multiple categories, including ledger and exception. Reject any
repeated or conflicting path classification, then retain the existing
deduplication and count logic only for validated unique classifications.
- Around line 71-73: Update the nested-module discovery pipeline in the find
invocation to stop suppressing errors: remove the stderr redirection and
trailing “|| true”, and explicitly prune the .git tree while searching. Preserve
the existing root exclusion, directory output, normalization, sorting, and
found-file behavior so invalid or unreadable roots cause the script to fail.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: fa991de2-50c0-4c6b-9cf8-1f3ebfdad1e4

📥 Commits

Reviewing files that changed from the base of the PR and between e41e388 and a0b4428.

📒 Files selected for processing (4)
  • .github/workflows/build-test.yml
  • tools/ci/check-nested-modules
  • tools/ci/nested-modules.txt
  • tools/ci/test-check-nested-modules

Comment thread tools/ci/check-nested-modules Outdated
Comment thread tools/ci/check-nested-modules
Comment thread tools/ci/check-nested-modules Outdated
Three review findings on the nested-module guard, all cases where it
could report a clean result it had not actually established.

A row naming a category with no path was silently skipped, so a typo
could quietly shrink the guard's coverage while it still passed. It now
reports the file and line and exits 2.

Category files were not deduplicated, only the combined list was. A
repeated `ledger svc/a` inflated the backlog count, and the same path
classified as both `ledger` and `exception` inflated both while passing,
misreporting how much of the migration is outstanding. One path now maps
to exactly one category.

Discovery suppressed find's errors and ended with `|| true`, so an
unreadable tree produced a partial inventory rather than a failure. That
is the same false-green pattern this guard exists to prevent, so errors
now terminate and `.git` is pruned explicitly instead.

Each is covered by a test, including that a MODULE.bazel planted inside
.git is pruned rather than discovered. One of those tests initially
asserted the wrong message because it passed /dev/null as the ledger,
which is not a regular file, so the script exited earlier than intended;
the fixture is a real empty file now.

Co-authored-by: Balaji Ganesan <bganesan@nvidia.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@tools/ci/test-check-nested-modules`:
- Line 134: Update the test command around the nested-module check to create a
temporary directory, remove it, and pass the resulting guaranteed-missing path
as the --root argument instead of the hard-coded /nonexistent-root-xyz value;
preserve the existing output capture and return-code assertions.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b8fc8e05-5442-4ceb-8aad-2267a88757d9

📥 Commits

Reviewing files that changed from the base of the PR and between a0b4428 and caaef1c.

📒 Files selected for processing (2)
  • tools/ci/check-nested-modules
  • tools/ci/test-check-nested-modules
🚧 Files skipped from review as they are similar to previous changes (1)
  • tools/ci/check-nested-modules

Comment thread tools/ci/test-check-nested-modules
@balajinvda

Copy link
Copy Markdown
Contributor Author

All three findings fixed in the latest push, and each is covered by a test.

Missing path — a row naming a category with no path was silently skipped, so a typo could quietly shrink the guard's coverage while it still passed. Now reports file and line, exits 2.

Duplicate and conflicting classifications — only the combined list was deduplicated, not the per-category files. A repeated ledger svc/a inflated the backlog count, and the same path as both ledger and exception inflated both while passing. One path now maps to exactly one category.

Masked discovery failures — this was the important one. 2>/dev/null || true meant an unreadable tree produced a partial inventory rather than a failure, which is the same false-green pattern the guard exists to prevent. Errors now terminate, and .git is pruned explicitly rather than filtered after the fact. There's a test that plants a MODULE.bazel inside .git to confirm pruning works.

Worth noting one of the new tests initially asserted the wrong error because it passed /dev/null as the ledger — not a regular file, so the script exited earlier than intended and the test was checking a message it never reached. The fixture is a real empty file now.

Unrelated: the earlier bazel (root) failure on this PR was a network flake, two proxy.golang.org fetches hitting TLS handshake timeout, including on the cacheless retry.

@kristinapathak
kristinapathak added this pull request to the merge queue Jul 28, 2026
Merged via the queue into main with commit 4b280ef Jul 28, 2026
16 checks passed
@kristinapathak
kristinapathak deleted the feat/bazel-nested-module-guard branch July 28, 2026 20:24
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.

2 participants