Consolidate coding standards in CONTRIBUTING.md; tune review automation (#1519)

### What does this PR do?

Type of change: documentation + tooling

Consolidates the previously agent-only coding guidelines into
`CONTRIBUTING.md` so both human contributors and AI agents work from the
same source of truth, and tunes the `/claude review` and CodeRabbit
automation so they are advisory (approve-only, never blocking).

**Docs reorg**
- Move the content of `.agents/developer-guidelines.md` into
`CONTRIBUTING.md` as a new `📐 Coding standards` section plus a `Test
design principles` subsection under the existing test section. Delete
the now-redundant file.
- Add two new coding principles:
- **Imports at top of file** in both source and test files. In-function
imports are reserved for resolving circular imports or guarding optional
dependencies (e.g., TRT-LLM, Megatron-Core), with a brief comment naming
the reason.
- **`__all__` + `from .module import *`** in package `__init__.py` to
make the public API surface explicit at the definition site and keep
star-imports safe.
- Update `AGENTS.md` to point at the merged location and move the
agent-specific "use relative paths" rule into it. Drop the dangling
reference in `claude_review.yml`.

**AI Review automation**
- `/claude review` (`.github/workflows/claude_review.yml`):
- Step 1 of the mandatory workflow now reads prior Claude
comments/reviews so the bot doesn't duplicate already-raised findings.
- Add brief thoroughness directives (per-file category coverage,
cross-file dataflow trace for new/modified public symbols) to push more
issues into the first review pass.
- Replace the ambiguous "approve if no significant issues" line with an
explicit decision rule: `0 CRITICAL AND 0 IMPORTANT → approve`,
regardless of SUGGESTION count. SUGGESTIONs alone never block approval.
- **Never submits a formal "Request changes" review.** When issues are
found, posts a `--comment` review instead. Claude review is advisory and
must not block merges.
- CodeRabbit (`.coderabbit.yaml`):
- Enable `reviews.request_changes_workflow: true` so CodeRabbit can
formally approve PRs once its comments are resolved and pre-merge checks
pass. Despite the name, this setting never submits a blocking "Request
changes" review.
- Add a `tests/**/*.py` path_instruction encoding the imports-at-top
rule, lean-tests guidance, and correct test-directory placement.

### Usage

N/A — documentation and automation configuration.

### Testing

- `pre-commit run` ran clean on both commits (markdownlint, YAML format,
etc.).
- `/claude review` workflow changes will be validated on the next PR
that triggers it.
- CodeRabbit `tests/**/*.py` rule and approval behavior will be
exercised on the next PR touching tests.

### Before your PR is "*Ready for review*"

- Is this change backward compatible?: ✅
- If you copied code from any other sources or added a new PIP
dependency, did you follow guidance in `CONTRIBUTING.md`: N/A
- Did you write any new necessary tests?: N/A (docs + workflow config
only)
- Did you update
[Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?:
N/A
- Did you get Claude approval on this PR?: ❌ (will run `/claude review`
after PR opens)

### Additional Information

The previous `.agents/developer-guidelines.md` content was not
agent-specific — it described universal coding standards. Hiding it
under `.agents/` discouraged human contributors from reading it. The
merge into `CONTRIBUTING.md` makes it discoverable on the standard
GitHub PR-creation flow.

The shift to approve-only automated reviews keeps the signal (approvals
when clean, inline comments when issues are found) without giving the
bots formal merge-blocking authority — the existing pre-merge
`custom_checks` security gates remain the hard blockers.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Enhanced contribution guidelines with comprehensive coding standards
and new test design principles.
* Updated agents guidance to remove the legacy developer-guidelines
reference.

* **Chores**
* Enabled formal "request changes" workflow and added test-path review
rules in CI config.
* Refined GitHub Actions review workflow (timeout, review prompt,
single-pass requirements, and approval criteria).
  * Removed legacy developer-guidelines file.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/NVIDIA/Model-Optimizer/pull/1519?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com>
This commit is contained in:
Keval Morabia
2026-05-19 21:34:31 +05:30
committed by GitHub
parent 2b8defc14b
commit 8f1529abd3
5 changed files with 125 additions and 67 deletions
-58
View File
@@ -1,58 +0,0 @@
# Coding Principles
Guidelines for production code in ModelOpt. Key values: simplicity, modularity,
and conciseness.
## Principles
- **Prefer simple, surgical changes.** Touch only what the task requires. Avoid speculative
refactors, broad rewrites, and "while we're here" cleanups.
- **Design for simplicity and readability.** Choose the design that is easiest to understand and maintain.
Code is read top to bottom: put high-level behavior first, hide lower-level details behind well-named helpers,
and treat heavy branching as a signal to reconsider the design.
- **Prefer modular, composable solutions.** Avoid input-specific or case-specific hard-coding.
Use existing extension points when they fit. If none fit, add a simple, focused helper,
class, or plugin that cleanly captures the new behavior. Keep scope limited to known cases.
- **Respect inheritance boundaries.** Parent abstractions should define shared contracts and
shared behavior, not child-specific special cases.
- **Don't repeat yourself; keep a single source of truth.** Consolidate repeated logic or intent with a shared helper, API,
or abstraction when doing so keeps the design simpler. Avoid duplication that can drift out of sync.
- **Comment cautiously.** Comments should add context, not translate code into English.
Prefer making the code self-explanatory first. Use comments only for non-obvious
intent or constraints that remain unclear from the code. Apply this guidance to new
comments only; do not rewrite or delete existing comments just for style.
- **Document public APIs.** Public and higher-level APIs should have docstrings, including examples when useful.
Internal helpers should usually be self-documenting through clear names and structure.
- **Fix the bug cause, not the side effect.** For bug fixes, find the root cause instead of patching for its side effect.
- **Validate external input once.** Check types and values at the interface boundary. Internal code can trust those
checks and avoid redundant assertions.
- **Remove dead code.** Delete unused imports, unreachable branches, and obsolete helpers.
- **Use relative paths** from the repo root in commands and file references.
## Testing
- **Develop with focused tests.** During development, write as many focused
tests as needed, including lower-level unit tests or internal probes, to
understand and harden behavior.
- **Curate production tests and keep them lean.** Before staging or committing,
decide which tests should be checked in. Checked-in tests should document
expected behavior, protect against regressions, or flag backward-incompatible
behavior changes. Remove redundant lower-level tests when a higher-level test
already covers the same behavior, keeping CI/CD fast and lean.
## Performant AI Code
- **Keep tensor work on the GPU and avoid unnecessary CPU-GPU syncs.** Reading metadata such as `tensor.shape` is fine.
Avoid Python scalar extraction and operators such as `tensor.item()`, `float(tensor)`, or `min(tensor)` because they
can trigger CPU-GPU syncs. Use PyTorch tensor ops such as `tensor.min()` by default, and only extract Python scalars
when the CPU needs the value. Tensor-value-based Python branching can also break CUDA graphs.
- **Develop with distributed processing in mind.** Examples: Use `print_rank_0` or `warn_rank_0`
when possible to avoid noisy logs. Guard shared side effects, such as
file writes or shared state updates, against race conditions between ranks.
## Compatibility
- **Preserve config and checkpoint backward compatibility.** ModelOpt checkpoints include serialized
`ModeloptBaseConfig` instances such as `QuantizeConfig`. If these Pydantic-based configs change
without backward compatibility handling, older checkpoints may no longer load. Make breaking changes
explicit and intentional.
+17
View File
@@ -4,6 +4,8 @@ reviews:
profile: chill
collapse_walkthrough: true
poem: false
# Allow CodeRabbit to formally approve once its comments are resolved and pre-merge checks pass
request_changes_workflow: true
path_instructions:
- path: "modelopt/**/*.py"
instructions: &security_instructions |
@@ -25,6 +27,21 @@ reviews:
@NVIDIA/modelopt-setup-codeowners with an explicit justification in the PR description.
- path: "examples/**/*.py"
instructions: *security_instructions
- path: "tests/**/*.py"
instructions: |
Verify tests follow the conventions in CONTRIBUTING.md. Flag the following as
IMPORTANT issues:
1. Imports inside functions or test methods without explicit justification.
Imports belong at the top of the file so import errors surface at collection
time, not mid-test. The only acceptable in-function imports are for circular
imports or optional dependencies (e.g., TensorRT-LLM, Megatron-Core), and
those should carry a brief comment naming the reason.
2. Redundant lower-level tests that duplicate behavior already covered by a
higher-level test — checked-in tests should be lean and document expected
behavior, protect against regressions, or flag backward-incompatible changes.
3. Tests placed in the wrong directory for their cost profile (e.g., multi-minute
tests under tests/unit, which targets a few-seconds budget; GPU-requiring
tests under tests/unit instead of tests/gpu*).
auto_review:
auto_incremental_review: true
drafts: false
+36 -8
View File
@@ -23,7 +23,7 @@ jobs:
contains(github.event.comment.body, '/claude review') &&
contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 15
permissions:
contents: read
pull-requests: write
@@ -80,13 +80,18 @@ jobs:
BASE REF: origin/${{ steps.pr-info.outputs.base_ref }}
Mandatory workflow — never skip or reorder:
1. Read the PR diff first (gh pr diff).
2. Read AGENTS.md, .agents/developer-guidelines.md,
and CONTRIBUTING.md for project conventions, coding principles, and architecture.
3. For changed files under `modelopt/torch/<sub-package>/`, read the sub-package's
1. Read prior Claude activity on the PR so you don't duplicate already-raised
comments and can track which prior issues are now resolved:
`gh pr view $PR_NUMBER --repo $REPO --json comments,reviews`
Treat prior findings as context, not a ceiling — if you spot a genuinely new
issue this round, flag it.
2. Read the PR diff (gh pr diff).
3. Read AGENTS.md and CONTRIBUTING.md (including the Coding standards section)
for project conventions, coding principles, and architecture.
4. For changed files under `modelopt/torch/<sub-package>/`, read the sub-package's
`__init__.py` plus any `mode.py` / `config.py` to understand mode registration
and config schema.
4. Only then perform the review using that context.
5. Only then perform the review using that context.
You are performing a deep code review on a **NVIDIA Model Optimizer (ModelOpt)** PR.
ModelOpt is NVIDIA's open-source library for model optimization (quantization, pruning,
@@ -118,6 +123,19 @@ jobs:
## Review Procedure
**Aim for one pass.** Surface meaningful issues in this review so the author gets
one consolidated set of fixes.
**Cover each changed file across categories.** For each non-trivial changed file,
consider the categories below (Algorithm Correctness, Mode/State, Export, Backward
Compatibility, Performance) before moving on.
**Trace public symbols across files.** For new or modified public symbols
(functions, arguments, config fields, exported names), grep call sites in
`modelopt/`, `tests/`, and `examples/` before commenting. Many bugs here only
surface where the symbol meets its caller — mode registration, export paths,
restore logic.
1. Get PR metadata: `gh pr view $PR_NUMBER --repo $REPO --json title,body,baseRefName,headRefName,files,additions,deletions,changedFiles,author`
2. Get the full diff: `gh pr diff $PR_NUMBER --repo $REPO`
- For large PRs (>50 files), prioritize source code over config/lock/auto-generated files.
@@ -182,6 +200,10 @@ jobs:
- Memory regressions: double-allocating weights, holding tensors past their lifetime.
## Suggestions (Nice to Have)
SUGGESTIONs document non-blocking improvements and never block approval (see
Completion below). Raise them when genuinely useful; skip nits that aren't.
- Stale, imprecise, or misleading comments/docstrings — a wrong docstring is worse
than none.
- Missing shape/dtype assertions at module/parallelism boundaries where they would
@@ -208,5 +230,11 @@ jobs:
- Highlight the most impactful findings
- Overall assessment of the PR's risk level
If no significant issues are found, approve the PR:
gh pr review $PR_NUMBER --repo $REPO --approve --body "Claude review passed — no significant issues found. LGTM"
**Approval decision — use exact counts from your findings (no other thresholds):**
- `0 CRITICAL AND 0 IMPORTANT` → **approve**, regardless of SUGGESTION count.
SUGGESTIONs never block approval.
`gh pr review $PR_NUMBER --repo $REPO --approve --body "Claude review passed — no blocking issues found. LGTM"`
- `≥1 CRITICAL OR ≥1 IMPORTANT` → **post a comment review** summarizing the
issues found.
`gh pr review $PR_NUMBER --repo $REPO --comment --body "<summary of issues found>"`
+2 -1
View File
@@ -11,8 +11,9 @@ These instructions apply to AI-assisted work in this repository.
## Coding guidelines
- **Coding guide:** Code development and review require reading and following
[.agents/developer-guidelines.md](.agents/developer-guidelines.md);
the [coding standards in CONTRIBUTING.md](CONTRIBUTING.md#-coding-standards);
do not skip this step.
- **Use relative paths** from the repo root in commands and file references.
## Iterative development
+70
View File
@@ -42,6 +42,65 @@ To run the pre-commit hooks without committing, use:
pre-commit run --all-files
```
## 📐 Coding standards
Guidelines for production code in ModelOpt. Key values: simplicity, modularity,
and conciseness.
### Principles
- **Prefer simple, surgical changes.** Touch only what the task requires. Avoid speculative
refactors, broad rewrites, and "while we're here" cleanups.
- **Design for simplicity and readability.** Choose the design that is easiest to understand and maintain.
Code is read top to bottom: put high-level behavior first, hide lower-level details behind well-named helpers,
and treat heavy branching as a signal to reconsider the design.
- **Prefer modular, composable solutions.** Avoid input-specific or case-specific hard-coding.
Use existing extension points when they fit. If none fit, add a simple, focused helper,
class, or plugin that cleanly captures the new behavior. Keep scope limited to known cases.
- **Respect inheritance boundaries.** Parent abstractions should define shared contracts and
shared behavior, not child-specific special cases.
- **Don't repeat yourself; keep a single source of truth.** Consolidate repeated logic or intent with a shared helper, API,
or abstraction when doing so keeps the design simpler. Avoid duplication that can drift out of sync.
- **Comment cautiously.** Comments should add context, not translate code into English.
Prefer making the code self-explanatory first. Use comments only for non-obvious
intent or constraints that remain unclear from the code. Apply this guidance to new
comments only; do not rewrite or delete existing comments just for style.
- **Document public APIs.** Public and higher-level APIs should have docstrings, including examples when useful.
Internal helpers should usually be self-documenting through clear names and structure.
- **Fix the bug cause, not the side effect.** For bug fixes, find the root cause instead of patching for its side effect.
- **Validate external input once.** Check types and values at the interface boundary. Internal code can trust those
checks and avoid redundant assertions.
- **Remove dead code.** Delete unused imports, unreachable branches, and obsolete helpers.
- **Keep imports at the top of the file.** Place all imports at module top in both source
and test files so import errors surface at module load time rather than at runtime or
during a specific test. Put an import inside a function only when there is a concrete
reason: resolving a circular import that cannot be restructured, guarding an optional
dependency (e.g., TensorRT-LLM, Megatron-Core), or deferring an unusually heavy import
with explicit justification. Add a brief comment in those cases naming the reason.
- **Define the public API with `__all__` and re-export via `from .module import *`.**
Each module declares its public surface with `__all__ = [...]` at the top of the file.
Package `__init__.py` files re-export submodules with `from .module import *`. This
keeps the public API explicit at the source (next to the definitions), avoids
hand-maintained import lists in `__init__.py` drifting out of sync, and makes
star-imports safe by limiting them to the curated `__all__` names.
### Performant AI code
- **Keep tensor work on the GPU and avoid unnecessary CPU-GPU syncs.** Reading metadata such as `tensor.shape` is fine.
Avoid Python scalar extraction and operators such as `tensor.item()`, `float(tensor)`, or `min(tensor)` because they
can trigger CPU-GPU syncs. Use PyTorch tensor ops such as `tensor.min()` by default, and only extract Python scalars
when the CPU needs the value. Tensor-value-based Python branching can also break CUDA graphs.
- **Develop with distributed processing in mind.** Examples: Use `print_rank_0` or `warn_rank_0`
when possible to avoid noisy logs. Guard shared side effects, such as
file writes or shared state updates, against race conditions between ranks.
### Compatibility
- **Preserve config and checkpoint backward compatibility.** ModelOpt checkpoints include serialized
`ModeloptBaseConfig` instances such as `QuantizeConfig`. If these Pydantic-based configs change
without backward compatibility handling, older checkpoints may no longer load. Make breaking changes
explicit and intentional.
## Adding a new PIP dependency
Currently we have 2 places where we mention pip dependencies: [pyproject.toml](./pyproject.toml) for dependencies that are required for the ModelOpt library and `examples/<example-name>/requirements.txt` for dependencies that are required for the specific examples.
@@ -101,6 +160,17 @@ For broader repo validation and dependency setup, use [noxfile.py](./noxfile.py)
nox -s "unit-3.12(torch_211, tf_latest)"
```
### Test design principles
- **Develop with focused tests.** During development, write as many focused
tests as needed, including lower-level unit tests or internal probes, to
understand and harden behavior.
- **Curate production tests and keep them lean.** Before staging or committing,
decide which tests should be checked in. Checked-in tests should document
expected behavior, protect against regressions, or flag backward-incompatible
behavior changes. Remove redundant lower-level tests when a higher-level test
already covers the same behavior, keeping CI/CD fast and lean.
## ✍️ Signing your work
- We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original