Skip to content

refactor(config): centralize sparse config patch validation#609

Merged
binaryaaron merged 19 commits into
mainfrom
binaryaaron/pr596-02-config-patches
Jul 7, 2026
Merged

refactor(config): centralize sparse config patch validation#609
binaryaaron merged 19 commits into
mainfrom
binaryaaron/pr596-02-config-patches

Conversation

@binaryaaron

@binaryaaron binaryaaron commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Centralizes sparse config patch validation on SafeSynthesizerParameters.
  • Adds explicit dotted parameter lookup and ambiguity handling for flat config APIs.

Test plan

  • uv run pytest tests/config/test_parameters.py tests/config/test_autoconfig.py tests/sdk/test_config_builder.py -q
  • mise run typecheck

Related issue: #614

Summary by CodeRabbit

  • New Features
    • Added schema-aware configuration patching for sparse updates, including resume-time overrides (generation/evaluation/telemetry only when explicitly set).
    • Enhanced the SDK configuration builder to accept raw mappings and dotted canonical paths, plus legacy aliases alongside typed configs.
  • Bug Fixes
    • Improved handling of dotted and bare parameter names, including ambiguity/unknown detection and clearer duplicate/conflict errors.
    • Updated CLI override parsing for correct nested keys and ensured unknown overrides are ignored.
  • Documentation
    • Expanded guidance on dotted-path overrides, sparse sources/explicit values, and resume-time override behavior.
  • Tests
    • Added extensive coverage for patching, path resolution, builder inputs, CLI merging, and regressions.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR shifts configuration handling to schema-aware patches and canonical parameter paths, updates SDK and CLI entry points to consume raw mappings through typed constructors, and expands docs and tests for dotted names, aliasing, ambiguity, and runtime override behavior.

Changes

Patch-based config handling

Layer / File(s) Summary
Patch primitives and paths
src/nemo_safe_synthesizer/utils.py, src/nemo_safe_synthesizer/configurator/parameter_paths.py, src/nemo_safe_synthesizer/configurator/pydantic_compat.py, src/nemo_safe_synthesizer/configurator/parameter.py, src/nemo_safe_synthesizer/config/generate.py, STYLE_GUIDE.md
Shared merge helpers, parameter-path resolution, compatibility annotations, and patch-oriented config APIs were added or updated.
Patch compilation and application
src/nemo_safe_synthesizer/config/patch.py, tests/config/test_patch.py
Configuration patch objects, conflict handling, sparse-field preservation, and patch application behavior were added and tested.
Parameter model APIs
src/nemo_safe_synthesizer/config/parameters.py, tests/config/test_parameters.py, tests/config/test_generate.py
Parameters and SafeSynthesizerParameters now resolve dotted and bare names through schema-aware lookup, build and apply patches, and merge runtime overrides with explicit patch semantics.
SDK builder raw config flow
src/nemo_safe_synthesizer/sdk/config_builder.py, tests/sdk/test_config_builder.py
ConfigBuilder now accepts raw mappings, resolves section configs through config-source constructors, deep-copies incoming state, and assembles the final SafeSynthesizerParameters directly from normalized sections.
CLI overrides, autoconfig, and docs
src/nemo_safe_synthesizer/cli/utils.py, src/nemo_safe_synthesizer/config/autoconfig.py, src/nemo_safe_synthesizer/configurator/pydantic_click_options.py, docs/user-guide/configuration.md, tests/cli/test_utils.py, tests/configurator/test_pydantic_click_options.py
CLI override merging and autoconfig update assembly now route through typed config patches, and documentation describes dotted names, sparse values, and runtime override limits.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • NVIDIA-NeMo/Safe-Synthesizer#549: Updates resume-generation override handling, which is directly connected to the runtime override patching in this change.
  • NVIDIA-NeMo/Safe-Synthesizer#595: Changes structured-generation configuration handling in the same codepath that this PR now normalizes through alias-aware parameter resolution.

Suggested labels: refactor, test

Suggested reviewers: mckornfield

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.56% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: centralizing sparse config patch validation in config handling.
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 binaryaaron/pr596-02-config-patches

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

@binaryaaron
binaryaaron force-pushed the binaryaaron/pr596-02-config-patches branch 2 times, most recently from e51202e to 236ccf4 Compare June 24, 2026 18:18
@binaryaaron
binaryaaron marked this pull request as ready for review June 24, 2026 18:47
@binaryaaron
binaryaaron requested a review from a team as a code owner June 24, 2026 18:47
@greptile-apps

greptile-apps Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR centralizes sparse config patch validation into SafeSynthesizerParameters, replacing ad-hoc merge_dicts+model_validate patterns throughout the codebase with a unified CompiledConfigPatch / ParameterSchema subsystem that handles dotted paths, declared aliases, ambiguity detection, and precedence-ordered materialization in one place.

  • configurator/parameter_paths.py (new): ParameterSchema indexes every field and alias in a Parameters model tree, resolves bare/dotted/alias names, and normalizes alias keys in raw mappings before they reach the patch compiler.
  • config/patch.py (new): CompiledConfigPatch compiles PatchAssignment(path, value, origin, precedence) records, validates same-precedence parent-child and duplicate conflicts, materializes lowest-precedence-first, and restores model_fields_set recursively so exclude_unset semantics survive round-trips.
  • config/parameters.py + configurator/parameters.py: from_params resolves all four name forms; from_config_source is the new per-section entry point used by ConfigBuilder; has()/get() gain dotted-path support and ambiguity raising; parse_overrides raises on parent-child CLI conflicts instead of silently resolving them.

Confidence Score: 5/5

Safe to merge. The refactoring replaces multiple ad-hoc dict-merge paths with a single well-tested patch compiler; all existing semantics are preserved or deliberately improved with corresponding test coverage.

The two new modules are covered by extensive unit tests verifying conflict detection, precedence ordering, alias normalization, and model_fields_set restoration round-trips. The with_runtime_overrides rewrite is exercised by the new TestWithRuntimeOverrides suite. The autoconfig.py change is semantically equivalent to the old merge_dicts path. The only observable behavioral changes are deliberate and consistent with long-standing docstring intent.

No files require special attention. The _restore_model_fields_set function in config/patch.py mutates Pydantic's internal model_fields_set set directly — safe because it operates only on freshly-validated model instances — but worth keeping in mind if the team upgrades Pydantic to a version that changes how that set is exposed.

Important Files Changed

Filename Overview
src/nemo_safe_synthesizer/config/patch.py New file: schema-aware CompiledConfigPatch with precedence-ordered materialization, parent-child conflict detection, and model_fields_set restoration via _restore_model_fields_set.
src/nemo_safe_synthesizer/configurator/parameter_paths.py New file: ParameterSchema and ParameterPath primitives for dotted-path resolution, alias normalization, ambiguity detection, and recursive field indexing over Parameters model trees.
src/nemo_safe_synthesizer/config/parameters.py from_params now resolves dotted/bare/alias names via ParameterSchema; with_config_patch and from_config_patch replace manual merge_dicts calls; with_runtime_overrides rewired to CompiledConfigPatch.apply_to_full_model.
src/nemo_safe_synthesizer/configurator/parameters.py Parameters base gains parameter_aliases ClassVar, explicit_patch/apply_patch/from_config_source methods, and rewritten has()/get() with dotted-path support and ambiguity raising.
src/nemo_safe_synthesizer/sdk/config_builder.py _resolve_config replaced by Parameters.from_config_source per section; _resolve_nss_config simplified to direct SafeSynthesizerParameters() construction; _preflight_config initialised in both init branches.
src/nemo_safe_synthesizer/configurator/pydantic_click_options.py parse_overrides now uses insert_parameter_value which raises ValueError on parent-child path conflicts rather than silently resolving them; _NEGATION_PREFIX constant extracted.
src/nemo_safe_synthesizer/config/autoconfig.py _build_updated_params switches from merge_dicts+model_validate to self._config.with_config_patch; semantically equivalent since training/data/privacy params are plain dicts with only computed fields.
src/nemo_safe_synthesizer/config/generate.py _STRUCTURED_GENERATION_LEGACY_FIELDS renamed to parameter_aliases with canonical dotted-path format; legacy migration validator now delegates to ParameterSchema.normalize_aliases.
src/nemo_safe_synthesizer/configurator/pydantic_compat.py New file: unwrap_optional_annotation and nested_model_type helpers for annotation introspection supporting branch/leaf classification.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Entry points: from_params / from_config_patch / with_config_patch / from_config_source"] --> B["ParameterSchema.from_model(cls)"]
    B --> C{Name type?}
    C -->|dotted path| D["split_parameter_path → exact field or alias lookup"]
    C -->|bare name| E["top-level → alias → inferred leaf"]
    C -->|top-level field| F[ResolvedParameterName]
    D --> F
    E --> F
    E --> G["AmbiguousParameterName → ParameterError"]
    E --> H["UnknownParameterName → ParameterError"]
    F --> I["PatchAssignment(path, value, origin, precedence)"]
    I --> J["CompiledConfigPatch.from_paths(target_model, assignments)"]
    J --> K[_validate_conflicts]
    K -->|conflict| L[ParameterError]
    K -->|ok| M[CompiledConfigPatch]
    M --> N["combine(other) — merge two patches"]
    M --> O["materialize() — sort by precedence, _insert_value per assignment"]
    O --> P["apply / apply_to_full_model → model_validate + _restore_model_fields_set"]
    P --> Q["Validated Parameters with correct model_fields_set"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["Entry points: from_params / from_config_patch / with_config_patch / from_config_source"] --> B["ParameterSchema.from_model(cls)"]
    B --> C{Name type?}
    C -->|dotted path| D["split_parameter_path → exact field or alias lookup"]
    C -->|bare name| E["top-level → alias → inferred leaf"]
    C -->|top-level field| F[ResolvedParameterName]
    D --> F
    E --> F
    E --> G["AmbiguousParameterName → ParameterError"]
    E --> H["UnknownParameterName → ParameterError"]
    F --> I["PatchAssignment(path, value, origin, precedence)"]
    I --> J["CompiledConfigPatch.from_paths(target_model, assignments)"]
    J --> K[_validate_conflicts]
    K -->|conflict| L[ParameterError]
    K -->|ok| M[CompiledConfigPatch]
    M --> N["combine(other) — merge two patches"]
    M --> O["materialize() — sort by precedence, _insert_value per assignment"]
    O --> P["apply / apply_to_full_model → model_validate + _restore_model_fields_set"]
    P --> Q["Validated Parameters with correct model_fields_set"]
Loading

Reviews (11): Last reviewed commit: "refactor(config): dedupe patch helpers a..." | Re-trigger Greptile

Comment thread src/nemo_safe_synthesizer/config/parameters.py Outdated
Comment thread src/nemo_safe_synthesizer/configurator/parameters.py Outdated
@binaryaaron
binaryaaron force-pushed the binaryaaron/pr596-02-config-patches branch from 92c88ac to 2693728 Compare June 24, 2026 21:46
Comment thread src/nemo_safe_synthesizer/sdk/config_builder.py Outdated
Base automatically changed from binaryaaron/pr596-01-ty-bump to main June 25, 2026 22:36
@binaryaaron
binaryaaron requested a review from a team as a code owner June 25, 2026 22:36
@binaryaaron
binaryaaron requested a review from mckornfield June 25, 2026 23:12

@mckornfield mckornfield left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

did this PR get mashed together with the ty one? realized I was reviewing something I'd already seen lol. let me know when you have the other one merged and I can stamp this one

Comment thread src/nemo_safe_synthesizer/config/parameters.py Outdated
Comment thread src/nemo_safe_synthesizer/configurator/parameters.py Outdated
mckornfield
mckornfield previously approved these changes Jun 26, 2026
@binaryaaron
binaryaaron force-pushed the binaryaaron/pr596-02-config-patches branch from b38bbc1 to 8771759 Compare June 26, 2026 20:47
@coderabbitai coderabbitai Bot added refactor Internal restructuring with no behavior change test Test-only addition or change labels Jun 26, 2026
Comment thread src/nemo_safe_synthesizer/sdk/config_builder.py Fixed
Comment thread src/nemo_safe_synthesizer/sdk/config_builder.py Fixed
Comment thread src/nemo_safe_synthesizer/sdk/config_builder.py Fixed
Comment thread src/nemo_safe_synthesizer/sdk/config_builder.py Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3412ccef-ae01-432b-af69-8ca09d40f3ea

📥 Commits

Reviewing files that changed from the base of the PR and between b9dd6e7 and 8771759.

📒 Files selected for processing (8)
  • src/nemo_safe_synthesizer/cli/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py
  • src/nemo_safe_synthesizer/utils.py
  • tests/config/test_parameters.py
  • tests/sdk/test_config_builder.py
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: Unit Tests (3.12)
  • GitHub Check: Unit Tests (3.11)
  • GitHub Check: Unit Tests (3.13)
  • GitHub Check: Smoke Tests
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{md,markdown,py}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown,py}: Avoid decorative bold (**text**) in list items, body text, and docstrings; use structural cues (headers, list markers, colons, backticks) for emphasis instead
Use backticks for code identifiers, paths, and CLI commands in markdown and docstrings

Files:

  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/cli/utils.py
  • tests/config/test_parameters.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Place durable implementation guidance in function and class docstrings for public contracts and source comments for local invariants
Target Python 3.11–3.13 with modern syntax (X | Y, list[str], Self). Python 3.14+ is not supported

**/*.py: Source code must remain Python 3.11 syntax-compatible; do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic class/function parameters in shared package code
Use ruff for formatting and linting via mise run format and mise run check tasks; run formatting before committing
Use ty for type checking via mise run check task; ensure type hints are present and valid
New features must include tests; bug fixes must include regression tests

**/*.py: Use BaseSettings for env/CLI settings, prefer AliasChoices for per-field dual naming, and use env_prefix only for simple settings classes with a shared prefix.
Use Field(description=...) as the canonical field docstring for Pydantic models, and always include it.
Use assignment-style Field(default=..., description="...") as the default for model fields; prefer it over Annotated unless extra metadata is needed.
Use Annotated only when the field carries additional metadata beyond Field() (for example validators, reusable constrained aliases, nested-type constraints, or discriminated unions).
When Annotated is used, place defaults as bare assignments (= value), except default_factory, which should still use assignment-style Field(default_factory=...).
For immutable value objects and validators, prefer @dataclass(frozen=True); use mutable dataclasses only for builders, accumulators, and pipeline state.
Use field(default_factory=list) for mutable defaults; never use = [].
Use StrEnum for string-valued enums used in configs or serialization; use plain Enum for internal-only named constants.
Use observability.get_logger(__name__) for logging; do not call logging.getLogger() or structlog.get_logger() direc...

Files:

  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/cli/utils.py
  • tests/config/test_parameters.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py
**/test_*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use the unit marker instead of the deprecated unit_test marker for test identification

Files:

  • tests/sdk/test_config_builder.py
  • tests/config/test_parameters.py
tests/**

📄 CodeRabbit inference engine (.cursor/rules/repo-navigation.mdc)

tests/**: Mirror src/ directory structure in tests/ directory for test organization
Auto-mark tests by directory: tests/e2e/e2e, tests/smoke/smoke, otherwise default to unit

Mirror source code directory structure in tests directory (e.g., tests/training/, tests/generation/ parallel to source structure)

Files:

  • tests/sdk/test_config_builder.py
  • tests/config/test_parameters.py

⚙️ CodeRabbit configuration file

tests/**:

Testing Guide

Comprehensive testing reference for Safe-Synthesizer developers. Covers commands, markers, test data, fixtures, and gotchas.

Read First

  1. tests/conftest.py -- auto-marking, load_test_dataset/load_test_dataframe, fixture_mock_processor pattern
  2. pytest.ini -- markers, asyncio, timeout
  3. tests/evaluation/conftest.py -- most complex: Faker-based make_df, nullable dtype conversion
  4. tests/generation/conftest.py -- JSONL/schema fixtures, fixture_valid_iris_dataset_jsonl_and_schema

Running Tests

All mise test tasks, grouped by scope:

mise run test                              # Unit (excludes slow, e2e, and smoke)
mise run test:unit-slow                    # Unit tests including slow (excludes e2e and smoke)
mise run test:smoke                        # CPU smoke tests (~few min, no GPU required)
mise run test:smoke:gpu                    # All staged GPU smoke tests (requires CUDA)
mise run test:smoke:gpu:train-only
mise run test:smoke:gpu:generation
mise run test:smoke:gpu:resume
mise run test:smoke:gpu:structured-generation
mise run test:smoke:gpu:timeseries
mise run test:smoke:gpu:smollm2
mise run test:e2e                          # All e2e (requires CUDA) -- runs default + dp
mise run test:e2e:default                  # e2e default (no-DP) tests only
mise run test:e2e:dp                       # e2e DP tests only
mise run test:ci                           # CI unit tests with coverage (excludes slow, e2e, gpu, smoke)
mise run test:ci-slow                      # CI slow tests with coverage
mise run test:ci-container                 # CI tests in a Linux container (Docker/Podman)

Run a single test:

uv run --frozen pytest tests/path/test_file.py::test_name -vvs -n0

Test runner: uv run --frozen pytest -n auto --dist loadscope -vv...

Files:

  • tests/sdk/test_config_builder.py
  • tests/config/test_parameters.py
**/*.{py,sh,yaml,yml,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

All source files (.py, .sh, .yaml, .yml, .md) require SPDX copyright headers; mise run format adds them automatically

Files:

  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/cli/utils.py
  • tests/config/test_parameters.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py
tests/**/*.py

📄 CodeRabbit inference engine (tests/TESTING.md)

tests/**/*.py: Auto-mark tests based on file path: tests under /e2e/ get e2e marker, tests under /smoke/ get smoke marker, all others get unit marker (only if no category marker already present)
Every test should have exactly one category marker: unit, smoke, or e2e
Use pytest.mark.requires_gpu modifier on tests that need CUDA hardware
Use pytest.mark.vllm on tests using vLLM generation backend and ensure each vLLM test file runs in its own process for GPU memory isolation
Use pytest.mark.slow on long-running tests
Use pytest.mark.smollm2 for SmolLM2 Hub download tests to enable process isolation
Use pytest.mark.noautouse to skip autouse fixtures for specific tests
Use load_test_dataset(filename) helper to load test datasets from tests/stub_datasets/ as HuggingFace Dataset objects
Use load_test_dataframe(filename) helper to load test data files from tests/stub_datasets/ as pandas DataFrames
Convert pandas columns to nullable dtypes (pd.Int64Dtype(), pd.BooleanDtype()) before assigning np.nan values
Use fake.seed_instance(seed) and random.seed(seed) together for Faker-based test data reproducibility
When sharing methods across multiple test files, define them in conftest.py and import them using relative imports (e.g., from .conftest import train_with_sdk); note that importing from other test files like tests/cli/helpers.py does not work
Use fixture_mock_processor or fixture_mock_processor_without_valid_records for mocking ParsedResponse objects with valid_records, invalid_records, errors, and prompt_number fields
Use pytest.importorskip to gate tests on optional dependencies that require specific extras (e.g., sentence_transformers, vllm)
Run vLLM tests with separate pytest invocations (one per file) using -n 0 (single process) for GPU memory isolation, or use staged mise tasks for CI visibility
Print statements are allowed in tests (ruff T201 is suppressed for tests/ directory) and should...

Files:

  • tests/sdk/test_config_builder.py
  • tests/config/test_parameters.py

⚙️ CodeRabbit configuration file

Review tests against tests/TESTING.md. Check marker usage, fixture naming, tmp_path usage, determinism, and GPU/vLLM process-isolation requirements. Flag slop tests that only check that code runs, assert result is not None when stronger invariants exist, over-mock internal implementation details, patch around the bug instead of reproducing it, or add broad snapshot/golden churn without a clear contract. Flag change detector tests that fail on harmless refactors, formatting, record ordering, incidental wording, or private implementation details without demonstrating a behavior regression. Prefer existing fixtures or focused new fixtures for repeated setup; keep tests DRY when reasonable without making the behavior under test opaque. print() is allowed in tests.

Files:

  • tests/sdk/test_config_builder.py
  • tests/config/test_parameters.py
**/*

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

**/*: Every source file must include the required SPDX copyright and license header; use HTML comments for Markdown, hash comments for .py, .sh, .yaml, and .yml, and hash-comment headers inside YAML frontmatter for Markdown files with frontmatter.
Ensure files end with a newline and have no trailing whitespace; use a single space between sentences.

Files:

  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/cli/utils.py
  • tests/config/test_parameters.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py

⚙️ CodeRabbit configuration file

**/*: Review as a senior maintainer for NeMo Safe Synthesizer. Prioritize issues that can change behavior, break user workflows, weaken privacy guarantees, hide failures, make tests unreliable, or create maintenance risk. Avoid generic style commentary unless it points to a concrete project convention that automated tools will not catch.
Comment only when the finding is actionable and tied to changed code. For each finding, state the impact, the condition that triggers it, and the smallest practical fix. Prefer one precise comment over broad advice. Do not ask for refactors outside the PR scope unless the changed code creates the problem.
Review type guidance: - Potential issue: use for correctness bugs, data loss, privacy leaks,
security risks, broken public APIs, invalid config behavior, missing
validation, hidden failures, nondeterministic tests, or CI breakage.

  • Refactor suggestion: use for local maintainability problems introduced
    by the diff when they have clear future cost, such as duplicated setup,
    unclear boundaries, over-mocking, avoidable complexity, or opaque test
    helpers.
  • Nitpick: avoid in chill mode. Do not emit formatting, import-order,
    wording, or style-only comments unless automated tools cannot catch the
    issue and it affects maintainability.

Severity guidance: - Critical: security/privacy leaks, data loss, training/test/holdout
contamination, or broken release/package/core pipeline execution.

  • Major: incorrect generation/training/evaluation behavior, broken
    CLI/SDK public API, invalid config defaults or validators, or GPU/vLLM
    cleanup and process-isolation bugs likely to fail CI or production
    runs.
  • Minor: localized bugs, missing focused tests for changed behavior, or
    bad test patterns that weaken regression coverage.
  • Trivial: small cleanup with no behavior impact. Usually suppress in
    chill mode.
  • Info: context only. Avoid unless it helps reviewers understand risk.
    Safe-Synthesizer-specific review focus: - Data ...

Files:

  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/cli/utils.py
  • tests/config/test_parameters.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py
**

⚙️ CodeRabbit configuration file

**:

AGENTS.md

Guide for AI agents (Cursor, Windsurf, Claude Code, etc.) working in the Safe-Synthesizer repo.

This project loads local developer preferences from @AGENTS.local.md. You MUST read this file if it exists and give its instructions top priority.

Skills

Repo-specific skills live in .agents/skills/; see .agents/README.md for the catalog. Read a skill when the task matches its scope instead of copying workflow details into this file.

Durable implementation guidance belongs with the code it describes: function and class docstrings for public contracts and source comments for local invariants. Test-suite guidance belongs in tests/TESTING.md.

Repo Conventions

See STYLE_GUIDE.md for detailed code style conventions (Python, markdown, Dockerfiles, shell scripts, testing, config files, docstrings).

Use uv for everything -- never pip or raw python. Python 3.11–3.13 with modern syntax (X | Y, list[str], Self). Python 3.14+ is not supported.

Common commands: mise run test (unit tests), mise run format (auto-fix formatting + lint + copyright), mise run check (read-only local quality checks), mise run validate (pre-PR quality, lock, and CI unit checks), mise run typecheck (ty only). Always use mise tasks or the wrapper scripts in tools/ instead of running ruff or ty directly. Use uv run for Python execution. When in doubt, inspect mise tasks and pytest --markers.

The canonical uv sync command for a full GPU/dev environment is:

uv sync --frozen --extra cu129 --extra engine --group dev

Bare uv sync --frozen (without extras) installs an incomplete environment -- ty, import checks, and GPU tests will fail.

Feature branches off main. Branch names often include an issue number prefix (e.g., <author>/123-short-name).

Do ...

Files:

  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/cli/utils.py
  • tests/config/test_parameters.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py
src/nemo_safe_synthesizer/**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

API reference pages are auto-generated from Python docstrings using Google-style format; write docstrings in src/nemo_safe_synthesizer/ and they will appear in the reference/

Files:

  • src/nemo_safe_synthesizer/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/cli/utils.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py
src/**/*.py

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

src/**/*.py: Use relative imports inside src/, for example from ..observability import get_logger.
Every directory under src/ that contains Python files must include an __init__.py file.

Files:

  • src/nemo_safe_synthesizer/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/cli/utils.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py

⚙️ CodeRabbit configuration file

Review library code against STYLE_GUIDE.md. Focus on behavior, API contracts, error handling, resource cleanup, typing, logging, and user-facing failures. Public APIs and nontrivial functions need Google-style docstrings.

Files:

  • src/nemo_safe_synthesizer/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/cli/utils.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py
src/nemo_safe_synthesizer/config/**/*.py

⚙️ CodeRabbit configuration file

Treat config changes as user-facing API changes. Check Pydantic field descriptions, defaults, validators, aliases, override behavior, CLI help text impact, YAML compatibility, and documented parameter semantics.

Files:

  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/config/parameters.py
src/nemo_safe_synthesizer/configurator/**/*.py

⚙️ CodeRabbit configuration file

Review Pydantic-to-Click mapping carefully. Check option names, type conversion, nullable sub-config behavior, validation errors, help text, and compatibility with parse_overrides().

Files:

  • src/nemo_safe_synthesizer/configurator/parameters.py
🧠 Learnings (1)
📚 Learning: 2026-05-27T22:20:37.354Z
Learnt from: kendrickb-nvidia
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 520
File: tests/generation/test_vllm_backend.py:556-587
Timestamp: 2026-05-27T22:20:37.354Z
Learning: In NVIDIA-NeMo/Safe-Synthesizer, `tests/conftest.py`’s `pytest_collection_modifyitems` hook applies pytest category markers automatically based on each test file’s path: tests under `/e2e/` get `pytest.mark.e2e`, tests under `/smoke/` get `pytest.mark.smoke`, and all other tests get `pytest.mark.unit`. Therefore, when reviewing pytest tests outside `tests/e2e/` and `tests/smoke/`, do not flag missing explicit `pytest.mark.unit` decorators on test classes/functions as an issue (the hook will add them during collection). If a new test directory/category is introduced, ensure the hook is updated so it’s categorized correctly.

Applied to files:

  • tests/sdk/test_config_builder.py
  • tests/config/test_parameters.py
🪛 Ruff (0.15.18)
tests/config/test_parameters.py

[warning] 147-147: Pattern passed to match= contains metacharacters but is neither escaped nor raw

(RUF043)


[warning] 176-176: Pattern passed to match= contains metacharacters but is neither escaped nor raw

(RUF043)


[warning] 181-181: Pattern passed to match= contains metacharacters but is neither escaped nor raw

(RUF043)


[warning] 235-235: Pattern passed to match= contains metacharacters but is neither escaped nor raw

(RUF043)


[warning] 250-250: Pattern passed to match= contains metacharacters but is neither escaped nor raw

(RUF043)

🔇 Additional comments (8)
src/nemo_safe_synthesizer/utils.py (1)

16-16: LGTM!

Also applies to: 263-272

src/nemo_safe_synthesizer/config/parameters.py (1)

8-11: LGTM!

Also applies to: 28-46, 73-104, 234-273, 276-311

src/nemo_safe_synthesizer/configurator/parameters.py (1)

34-42: LGTM!

Also applies to: 114-185, 254-254

tests/config/test_parameters.py (1)

4-15: LGTM!

Also applies to: 139-144, 185-229, 239-244, 254-263

src/nemo_safe_synthesizer/sdk/config_builder.py (1)

9-9: LGTM!

Also applies to: 43-58, 102-131, 139-291

tests/sdk/test_config_builder.py (1)

1-58: LGTM!

src/nemo_safe_synthesizer/cli/utils.py (1)

27-27: LGTM!

Also applies to: 435-452

src/nemo_safe_synthesizer/config/autoconfig.py (1)

23-23: LGTM!

Also applies to: 306-312

Comment thread src/nemo_safe_synthesizer/config/parameters.py Outdated
Comment thread src/nemo_safe_synthesizer/sdk/config_builder.py Outdated
Comment thread tests/config/test_parameters.py Outdated
@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

@github-actions github-actions Bot added area:dev-ex Affects build or dev experience area:docs labels Jun 30, 2026
Comment thread src/nemo_safe_synthesizer/config/parameters.py Fixed
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
@binaryaaron
binaryaaron force-pushed the binaryaaron/pr596-02-config-patches branch from 7b798be to 596c793 Compare July 1, 2026 20:22
@coderabbitai coderabbitai Bot added the test Test-only addition or change label Jul 1, 2026
Comment thread src/nemo_safe_synthesizer/configurator/parameter_paths.py Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/nemo_safe_synthesizer/configurator/parameter_paths.py (1)

240-248: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject alias writes through non-mapping parents.

Line 246 currently turns an existing scalar or None parent into {}, so a legacy alias can hide an explicitly invalid canonical value instead of surfacing a config error. Raise when the branch key already exists but is not a mapping/model.

Proposed fix
-    for part in path.parts[:-1]:
+    for index, part in enumerate(path.parts[:-1]):
         branch = current.get(part)
         if isinstance(branch, BaseModel):
             nested = branch.model_dump(exclude_unset=True)
         elif isinstance(branch, Mapping):
             nested = dict(branch)
+        elif part in current:
+            prefix = ".".join(path.parts[: index + 1])
+            raise ParameterError(
+                f"Cannot apply parameter alias {str(path)!r}: {prefix!r} already has a non-mapping value."
+            )
         else:
             nested = {}

As per path instructions, invalid config behavior that hides failures should be prioritized.

Source: Path instructions


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7b5ed339-0b89-4564-997a-88084794c686

📥 Commits

Reviewing files that changed from the base of the PR and between 7b798be and 596c793.

📒 Files selected for processing (20)
  • STYLE_GUIDE.md
  • docs/user-guide/configuration.md
  • src/nemo_safe_synthesizer/cli/utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/config/generate.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • src/nemo_safe_synthesizer/config/patch.py
  • src/nemo_safe_synthesizer/configurator/parameter.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • src/nemo_safe_synthesizer/configurator/pydantic_click_options.py
  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py
  • src/nemo_safe_synthesizer/utils.py
  • tests/cli/test_utils.py
  • tests/config/test_generate.py
  • tests/config/test_parameters.py
  • tests/config/test_patch.py
  • tests/configurator/test_pydantic_click_options.py
  • tests/sdk/test_config_builder.py
✅ Files skipped from review due to trivial changes (2)
  • STYLE_GUIDE.md
  • src/nemo_safe_synthesizer/configurator/parameter.py
🚧 Files skipped from review as they are similar to previous changes (13)
  • tests/config/test_generate.py
  • tests/configurator/test_pydantic_click_options.py
  • src/nemo_safe_synthesizer/utils.py
  • tests/cli/test_utils.py
  • src/nemo_safe_synthesizer/config/autoconfig.py
  • src/nemo_safe_synthesizer/cli/utils.py
  • src/nemo_safe_synthesizer/config/parameters.py
  • tests/config/test_parameters.py
  • src/nemo_safe_synthesizer/configurator/pydantic_click_options.py
  • src/nemo_safe_synthesizer/configurator/parameters.py
  • docs/user-guide/configuration.md
  • tests/config/test_patch.py
  • src/nemo_safe_synthesizer/sdk/config_builder.py
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{md,markdown,py}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown,py}: Avoid decorative bold (**text**) in list items, body text, and docstrings; use structural cues (headers, list markers, colons, backticks) for emphasis instead
Use backticks for code identifiers, paths, and CLI commands in markdown and docstrings

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/config/generate.py
  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/config/patch.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Place durable implementation guidance in function and class docstrings for public contracts and source comments for local invariants
Target Python 3.11–3.13 with modern syntax (X | Y, list[str], Self). Python 3.14+ is not supported

**/*.py: Source code must remain Python 3.11 syntax-compatible; do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic class/function parameters in shared package code
Use ruff for formatting and linting via mise run format and mise run check tasks; run formatting before committing
Use ty for type checking via mise run check task; ensure type hints are present and valid
New features must include tests; bug fixes must include regression tests

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/config/generate.py
  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/config/patch.py
**/*.{py,sh,yaml,yml,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

All source files (.py, .sh, .yaml, .yml, .md) require SPDX copyright headers; mise run format adds them automatically

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/config/generate.py
  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/config/patch.py
src/nemo_safe_synthesizer/**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

API reference pages are auto-generated from Python docstrings using Google-style format; write docstrings in src/nemo_safe_synthesizer/ and they will appear in the reference/

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/config/generate.py
  • src/nemo_safe_synthesizer/config/patch.py
src/**/*.py

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

src/**/*.py: __all__ defines the public API surface; identifiers with a leading _ are private and may change without notice.
Use BaseSettings for env/CLI settings, prefer AliasChoices for per-field aliases when a field must respond to both its Python name and an env var name, and use env_prefix only for simple settings classes with a shared prefix.
Always include Field(description=...) for Pydantic model fields as the canonical field docstring.
Prefer assignment-style Field(...) for Pydantic model fields; use Annotated only when the field carries additional metadata beyond Field(), and use a bare assignment for defaults unless default_factory is needed.
Use @dataclass(frozen=True) for immutable value objects and validators; mutable dataclasses are acceptable for builders, accumulators, and pipeline state.
Use field(default_factory=list) for mutable dataclass defaults; never use =[].
Use StrEnum for string-valued enums used in configs/serialization, and plain Enum for internal-only named constants.
Use observability.get_logger(__name__) for logging; never call logging.getLogger() or structlog.get_logger() directly.
Never use print() for operational output; use click.echo() for CLI output or sys.stdout.write() for raw tool output.
Use extra={...} for log data meant for downstream querying or aggregation; use f-strings only for human-readable context.
Raise from the custom error hierarchy (SafeSynthesizerError, UserError, DataError, ParameterError, GenerationError, InternalError) instead of ad hoc exceptions.
Use native Python 3.11 typing syntax (X | Y, list[str], Self, Sequence/Mapping/Iterable, Protocol, TypeIs) and avoid Python 3.12-only syntax such as PEP 695 type statements and bracketed generic parameters.
Guard heavy imports such as pandas, torch, and transformers with TYPE_CHECKING when they are only needed for typing.
Prefer match/case for dispatch on types or tagged values...

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/config/generate.py
  • src/nemo_safe_synthesizer/config/patch.py

⚙️ CodeRabbit configuration file

Review library code against STYLE_GUIDE.md. Focus on behavior, API contracts, error handling, resource cleanup, typing, logging, and user-facing failures. Public APIs and nontrivial functions need Google-style docstrings.

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/config/generate.py
  • src/nemo_safe_synthesizer/config/patch.py
**/*.{py,sh,yaml,yml,md,toml}

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Every source file must include the repository SPDX copyright and license header, with Markdown using HTML comments unless the file begins with YAML frontmatter.

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/config/generate.py
  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/config/patch.py
**/*

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Keep files newline-terminated, free of trailing whitespace, with single spaces between sentences and line length within the configured limit.

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/config/generate.py
  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/config/patch.py

⚙️ CodeRabbit configuration file

**/*: Review as a senior maintainer for NeMo Safe Synthesizer. Prioritize issues that can change behavior, break user workflows, weaken privacy guarantees, hide failures, make tests unreliable, or create maintenance risk. Avoid generic style commentary unless it points to a concrete project convention that automated tools will not catch.
Comment only when the finding is actionable and tied to changed code. For each finding, state the impact, the condition that triggers it, and the smallest practical fix. Prefer one precise comment over broad advice. Do not ask for refactors outside the PR scope unless the changed code creates the problem.
Review type guidance: - Potential issue: use for correctness bugs, data loss, privacy leaks,
security risks, broken public APIs, invalid config behavior, missing
validation, hidden failures, nondeterministic tests, or CI breakage.

  • Refactor suggestion: use for local maintainability problems introduced
    by the diff when they have clear future cost, such as duplicated setup,
    unclear boundaries, over-mocking, avoidable complexity, or opaque test
    helpers.
  • Nitpick: avoid in chill mode. Do not emit formatting, import-order,
    wording, or style-only comments unless automated tools cannot catch the
    issue and it affects maintainability.

Severity guidance: - Critical: security/privacy leaks, data loss, training/test/holdout
contamination, or broken release/package/core pipeline execution.

  • Major: incorrect generation/training/evaluation behavior, broken
    CLI/SDK public API, invalid config defaults or validators, or GPU/vLLM
    cleanup and process-isolation bugs likely to fail CI or production
    runs.
  • Minor: localized bugs, missing focused tests for changed behavior, or
    bad test patterns that weaken regression coverage.
  • Trivial: small cleanup with no behavior impact. Usually suppress in
    chill mode.
  • Info: context only. Avoid unless it helps reviewers understand risk.
    Safe-Synthesizer-specific review focus: - Data ...

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/config/generate.py
  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/config/patch.py
**

⚙️ CodeRabbit configuration file

**:

AGENTS.md

Guide for AI agents (Cursor, Windsurf, Claude Code, etc.) working in the Safe-Synthesizer repo.

This project loads local developer preferences from @AGENTS.local.md. You MUST read this file if it exists and give its instructions top priority.

Skills

Repo-specific skills live in .agents/skills/; see .agents/README.md for the catalog. Read a skill when the task matches its scope instead of copying workflow details into this file.

Durable implementation guidance belongs with the code it describes: function and class docstrings for public contracts and source comments for local invariants. Test-suite guidance belongs in tests/TESTING.md.

Repo Conventions

See STYLE_GUIDE.md for detailed code style conventions (Python, markdown, Dockerfiles, shell scripts, testing, config files, docstrings).

Use uv for everything -- never pip or raw python. Python 3.11–3.13 with modern syntax (X | Y, list[str], Self). Python 3.14+ is not supported.

Common commands: mise run test (unit tests), mise run format (auto-fix formatting + lint + copyright), mise run check (read-only local quality checks), mise run validate (pre-PR quality, lock, and CI unit checks), mise run typecheck (ty only). Always use mise tasks or the wrapper scripts in tools/ instead of running ruff or ty directly. Use uv run for Python execution. When in doubt, inspect mise tasks and pytest --markers.

The canonical uv sync command for a full GPU/dev environment is:

uv sync --frozen --extra cu129 --extra engine --group dev

Bare uv sync --frozen (without extras) installs an incomplete environment -- ty, import checks, and GPU tests will fail.

Feature branches off main. Branch names often include an issue number prefix (e.g., <author>/123-short-name).

Do ...

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
  • src/nemo_safe_synthesizer/config/generate.py
  • tests/sdk/test_config_builder.py
  • src/nemo_safe_synthesizer/config/patch.py
src/nemo_safe_synthesizer/configurator/**/*.py

⚙️ CodeRabbit configuration file

Review Pydantic-to-Click mapping carefully. Check option names, type conversion, nullable sub-config behavior, validation errors, help text, and compatibility with parse_overrides().

Files:

  • src/nemo_safe_synthesizer/configurator/pydantic_compat.py
  • src/nemo_safe_synthesizer/configurator/parameter_paths.py
src/nemo_safe_synthesizer/config/**/*.py

⚙️ CodeRabbit configuration file

Treat config changes as user-facing API changes. Check Pydantic field descriptions, defaults, validators, aliases, override behavior, CLI help text impact, YAML compatibility, and documented parameter semantics.

Files:

  • src/nemo_safe_synthesizer/config/generate.py
  • src/nemo_safe_synthesizer/config/patch.py
**/test_*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use the unit marker instead of the deprecated unit_test marker for test identification

Files:

  • tests/sdk/test_config_builder.py
tests/**

📄 CodeRabbit inference engine (.cursor/rules/repo-navigation.mdc)

tests/**: Mirror src/ directory structure in tests/ directory for test organization
Auto-mark tests by directory: tests/e2e/e2e, tests/smoke/smoke, otherwise default to unit

Mirror source code directory structure in tests directory (e.g., tests/training/, tests/generation/ parallel to source structure)

Files:

  • tests/sdk/test_config_builder.py

⚙️ CodeRabbit configuration file

tests/**:

Testing Guide

Comprehensive testing reference for Safe-Synthesizer developers. Covers commands, markers, test data, fixtures, and gotchas.

Read First

  1. tests/conftest.py -- auto-marking, load_test_dataset/load_test_dataframe, fixture_mock_processor pattern
  2. pytest.ini -- markers, asyncio, timeout
  3. tests/evaluation/conftest.py -- most complex: Faker-based make_df, nullable dtype conversion
  4. tests/generation/conftest.py -- JSONL/schema fixtures, fixture_valid_iris_dataset_jsonl_and_schema

Running Tests

All mise test tasks, grouped by scope:

mise run test                              # Unit (excludes slow, e2e, and smoke)
mise run test:unit-slow                    # Unit tests including slow (excludes e2e and smoke)
mise run test:smoke                        # CPU smoke tests (~few min, no GPU required)
mise run test:smoke:gpu                    # All staged GPU smoke tests (requires CUDA)
mise run test:smoke:gpu:train-only
mise run test:smoke:gpu:generation
mise run test:smoke:gpu:resume
mise run test:smoke:gpu:structured-generation
mise run test:smoke:gpu:timeseries
mise run test:smoke:gpu:smollm2
mise run test:e2e                          # All e2e (requires CUDA) -- runs default + dp
mise run test:e2e:default                  # e2e default (no-DP) tests only
mise run test:e2e:dp                       # e2e DP tests only
mise run test:ci                           # CI unit tests with coverage (excludes slow, e2e, gpu, smoke)
mise run test:ci-slow                      # CI slow tests with coverage
mise run test:ci-container                 # CI tests in a Linux container (Docker/Podman)

Run a single test:

uv run --frozen pytest tests/path/test_file.py::test_name -vvs -n0

Test runner: uv run --frozen pytest -n auto --dist loadscope -vv...

Files:

  • tests/sdk/test_config_builder.py
tests/**/*.py

📄 CodeRabbit inference engine (tests/TESTING.md)

tests/**/*.py: Auto-mark tests based on file path: tests under /e2e/ get e2e marker, tests under /smoke/ get smoke marker, all others get unit marker (only if no category marker already present)
Every test should have exactly one category marker: unit, smoke, or e2e
Use pytest.mark.requires_gpu modifier on tests that need CUDA hardware
Use pytest.mark.vllm on tests using vLLM generation backend and ensure each vLLM test file runs in its own process for GPU memory isolation
Use pytest.mark.slow on long-running tests
Use pytest.mark.smollm2 for SmolLM2 Hub download tests to enable process isolation
Use pytest.mark.noautouse to skip autouse fixtures for specific tests
Use load_test_dataset(filename) helper to load test datasets from tests/stub_datasets/ as HuggingFace Dataset objects
Use load_test_dataframe(filename) helper to load test data files from tests/stub_datasets/ as pandas DataFrames
Convert pandas columns to nullable dtypes (pd.Int64Dtype(), pd.BooleanDtype()) before assigning np.nan values
Use fake.seed_instance(seed) and random.seed(seed) together for Faker-based test data reproducibility
When sharing methods across multiple test files, define them in conftest.py and import them using relative imports (e.g., from .conftest import train_with_sdk); note that importing from other test files like tests/cli/helpers.py does not work
Use fixture_mock_processor or fixture_mock_processor_without_valid_records for mocking ParsedResponse objects with valid_records, invalid_records, errors, and prompt_number fields
Use pytest.importorskip to gate tests on optional dependencies that require specific extras (e.g., sentence_transformers, vllm)
Run vLLM tests with separate pytest invocations (one per file) using -n 0 (single process) for GPU memory isolation, or use staged mise tasks for CI visibility
Print statements are allowed in tests (ruff T201 is suppressed for tests/ directory) and should...

Files:

  • tests/sdk/test_config_builder.py

⚙️ CodeRabbit configuration file

Review tests against tests/TESTING.md. Check marker usage, fixture naming, tmp_path usage, determinism, and GPU/vLLM process-isolation requirements. Flag slop tests that only check that code runs, assert result is not None when stronger invariants exist, over-mock internal implementation details, patch around the bug instead of reproducing it, or add broad snapshot/golden churn without a clear contract. Flag change detector tests that fail on harmless refactors, formatting, record ordering, incidental wording, or private implementation details without demonstrating a behavior regression. Prefer existing fixtures or focused new fixtures for repeated setup; keep tests DRY when reasonable without making the behavior under test opaque. print() is allowed in tests.

Files:

  • tests/sdk/test_config_builder.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA-NeMo/Safe-Synthesizer

Timestamp: 2026-07-01T20:22:38.492Z
Learning: Use American English spelling in code, docs, configs, and tests (for example, "initialize" not "initialise", "recognize" not "recognise", "color" not "colour").
📚 Learning: 2026-05-27T22:20:37.354Z
Learnt from: kendrickb-nvidia
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 520
File: tests/generation/test_vllm_backend.py:556-587
Timestamp: 2026-05-27T22:20:37.354Z
Learning: In NVIDIA-NeMo/Safe-Synthesizer, `tests/conftest.py`’s `pytest_collection_modifyitems` hook applies pytest category markers automatically based on each test file’s path: tests under `/e2e/` get `pytest.mark.e2e`, tests under `/smoke/` get `pytest.mark.smoke`, and all other tests get `pytest.mark.unit`. Therefore, when reviewing pytest tests outside `tests/e2e/` and `tests/smoke/`, do not flag missing explicit `pytest.mark.unit` decorators on test classes/functions as an issue (the hook will add them during collection). If a new test directory/category is introduced, ensure the hook is updated so it’s categorized correctly.

Applied to files:

  • tests/sdk/test_config_builder.py
🔇 Additional comments (6)
tests/sdk/test_config_builder.py (2)

1-252: LGTM!


244-252: 📐 Maintainability & Code Quality

No change needed: _classify_model_provider is internal state. This test is exercising the intended resolve() injection contract; there is no public builder API for setting this field.

			> Likely an incorrect or invalid review comment.
src/nemo_safe_synthesizer/configurator/parameter_paths.py (1)

1-237: LGTM!

Also applies to: 253-280

src/nemo_safe_synthesizer/configurator/pydantic_compat.py (1)

1-32: LGTM!

src/nemo_safe_synthesizer/config/generate.py (1)

7-7: LGTM!

Also applies to: 16-16, 275-287

src/nemo_safe_synthesizer/config/patch.py (1)

1-313: LGTM!

Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
mckornfield
mckornfield previously approved these changes Jul 1, 2026
…lution

Introduce PARAMETER_PATH_SEPARATOR and format_parameter_path as the single
source of truth for dotted parameter-path joins/splits, replacing scattered
"." literals across patch.py and the configurator. Also extract
_fields_ending_with and _ambiguous_error to remove duplicated bare-name
lookup and ambiguity-error formatting.

Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Extract _walk_parameter_models so _iter_parameter_fields and
_iter_parameter_aliases share one pre-order descent. Replace the isinstance
chains in _set_parameter_value and normalize_aliases with match statements,
mirroring the existing resolution dispatch in require().

Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Behavior-preserving cleanup of the config/configurator patch layer:
- Extract _ensure_branch and _matching_field_paths helpers to remove
  duplicated logic in _insert_value and get()/has().
- Centralize the CLI negation prefix into _NEGATION_PREFIX and strip it
  via removeprefix at the consumer.
- Collapse assign-then-guard blocks with the walrus operator.
- Unpack (path, value) in get() instead of manual [0][1] indexing.

Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
@binaryaaron
binaryaaron added this pull request to the merge queue Jul 7, 2026
Merged via the queue into main with commit 26aa563 Jul 7, 2026
22 checks passed
@binaryaaron
binaryaaron deleted the binaryaaron/pr596-02-config-patches branch July 7, 2026 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:config area:dev-ex Affects build or dev experience area:docs area:sdk-cli area:tests refactor Internal restructuring with no behavior change test Test-only addition or change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants