Skip to content

feat(cli): add 'gym env validate' pre-flight config check (#1205 friction #12)#1599

Merged
wprazuch merged 3 commits into
mainfrom
wprazuch/ng-validate
Jun 25, 2026
Merged

feat(cli): add 'gym env validate' pre-flight config check (#1205 friction #12)#1599
wprazuch merged 3 commits into
mainfrom
wprazuch/ng-validate

Conversation

@wprazuch

@wprazuch wprazuch commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What

Adds gym env validate (+ ng_validate / nemo_gym_validate deprecated shims) — runs the full config parse with no Ray and no server subprocesses, then exits 0 (valid) / 1 (invalid) with a clean, rich-escaped message (no traceback). Returns in well under a second instead of after a ~30–60s Ray bootstrap.

gym env validate --config resources_servers/<env>/configs/<env>.yaml --config responses_api_models/<model>/configs/<model>.yaml
gym env validate --benchmark gsm8k --model-type openai_model

How

validate() lives in cli/env.py and is registered as env validate in the gym router (cli/main.py COMMANDS) with the same config-selection flags as env start (--config, --benchmark, --environment, --resources-server, --model-type, --search-dir, --model*). It reuses the same get_global_config_dict() parse path the other commands use, so the validation checks stay in sync:

  • config_paths resolution — missing/typo'd (#1488) and malformed (#1490)
  • server cross-references — unknown name: refs (#1561)
  • mandatory ??? values (#1575)
  • schema (BaseNeMoGymCLIConfig)

Wrapped in exit_cleanly_on_config_error (from #1609) so any ConfigError becomes a clean message + exit 1. A dummy policy_model is injected (the NO_MODEL parser config, as in gym list / env compose) so model interpolations like ${policy_base_url} resolve without real creds — validation is about config well-formedness; the real model is supplied by the --model* flags at run time.

Targets main

Originally drafted on the unified-CLI epic branch; rebuilt directly on main now that #1630 (and #1637/#1609/#1635/#1671) have merged. The old branch contents (a snapshot of the CLI refactor + unrelated CI commits) were superseded and replaced.

Scope note

The zero-server check (#1489, "nothing configured to run") is intentionally not part of validate: NO_MODEL injects a dummy model server (which would defeat the check), and "is anything configured to run" is a start-time concern already enforced by gym env start before Ray init. validate focuses on config well-formedness.

Why

Epic #1205 friction #12 (no config validation tooling) — the M1 "fast failure triage" deliverable. Config errors otherwise only surface after Ray starts (~30–60s).

Tests

  • test_cli_main.py: gym env validate --config X routes to nemo_gym.cli.env:validate with +config_paths=[X] (added to the parametrized config-command matrix).
  • test_cli.py: validate() prints OK on a valid config; a raised ConfigError becomes exit 1 (no traceback).
  • All test_cli + test_cli_main + test_cli_legacy pass (the only failures are the pre-existing Python-3.12 TestDidYouMean argparse issue on main); ruff + pre-commit clean. Smoke-tested end-to-end: ✓ Config is valid. on a real benchmark, clean error + exit 1 on a bad path, and the ng_validate deprecation shim.

@copy-pr-bot

copy-pr-bot Bot commented Jun 15, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

wprazuch added a commit that referenced this pull request Jun 16, 2026
Supersedes #1510; covers epic #1205 friction #8 + #12 and issues #1488,
#1489, #1490 in one place:

- #1488: missing config_paths entry -> ConfigPathNotFoundError (names entry +
  searched locations).
- #1490: malformed (non-list) config_paths -> MalformedConfigPathsError with
  the expected Hydra list syntax.
- #1489: zero configured servers -> NoServerInstancesError, raised in
  RunHelper.start() before Ray (covers ng_run AND e2e_rollout_collection).

All three subclass a new ConfigError base. A CLI decorator
(exit_cleanly_on_config_error) on run()/e2e_rollout_collection() turns any
ConfigError into a clean, rich-escaped message + exit 1 with NO traceback
(the explicit ask in #1488/#1489), while keeping them ordinary exceptions so
ng_validate (#1599) can still catch and format them. Zero-server check uses
validated server instances, not a raw key count.

Tests: deterministic tmp_path-based path-error tests (both-locations, dedup,
absolute), malformed-config_paths, zero-server, and the decorator
(ConfigError -> clean exit; non-ConfigError propagates).

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
@wprazuch wprazuch force-pushed the wprazuch/ng-validate branch from 621d0f0 to dc297fa Compare June 17, 2026 08:30
@wprazuch wprazuch changed the base branch from main to martas/1434 June 17, 2026 08:30
@wprazuch wprazuch changed the title feat(cli): add ng_validate pre-flight config check (#1205 friction #12) feat(cli): add 'gym env validate' pre-flight config check (#1205 friction #12) Jun 17, 2026
wprazuch added a commit that referenced this pull request Jun 17, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
@wprazuch wprazuch force-pushed the wprazuch/ng-validate branch from f44535d to 624d4cf Compare June 17, 2026 09:31
@wprazuch wprazuch changed the base branch from martas/1434 to wprazuch/ng-test-concurrency June 17, 2026 09:31
wprazuch added a commit that referenced this pull request Jun 22, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
@wprazuch wprazuch force-pushed the wprazuch/ng-test-concurrency branch from 2fdee46 to eebfcf8 Compare June 22, 2026 13:45
wprazuch added a commit that referenced this pull request Jun 22, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
wprazuch added a commit that referenced this pull request Jun 22, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
wprazuch added a commit that referenced this pull request Jun 22, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
wprazuch added a commit that referenced this pull request Jun 22, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
wprazuch added a commit that referenced this pull request Jun 22, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
@wprazuch wprazuch force-pushed the wprazuch/ng-validate branch from 624d4cf to 4ad73ce Compare June 22, 2026 13:46
wprazuch added a commit that referenced this pull request Jun 22, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
wprazuch added a commit that referenced this pull request Jun 22, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
wprazuch added a commit that referenced this pull request Jun 22, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
wprazuch added a commit that referenced this pull request Jun 22, 2026
Shared CI fixes for the martas/1434-stacked CLI work: pin uv (0.11.20 drops
pinned deps -> 7 servers fail; = #1576) and pull main's graphwalks
example_rollouts.jsonl (fixes its data validation). This branch is the base
for the ng_validate (#1599) and config-error (#1609) PRs so the fixes live in
one place. Drop when martas/1434 rebases on main.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
wprazuch added a commit that referenced this pull request Jun 25, 2026
…hs (#1205 #8/#12; #1488/#1489/#1490) (#1609)

## What

One coherent fix for the three `config_paths` failure modes, all failing
fast with a **clean message and no traceback**:

| Issue | Bad input | Before | After |
|-------|-----------|--------|-------|
| [#1488](#1488) | typo'd /
missing path | 7-frame `FileNotFoundError` | `Error: config_paths entry
'...' was not found. Looked in: ...` |
| [#1490](#1490) | scalar
instead of list | raw Pydantic `ValidationError` (+pydantic.dev URL) |
`Error: 'config_paths' must be a list of paths ...` |
| [#1489](#1489) | empty /
omitted (zero servers) | Ray starts, hangs until SIGTERM | `Error: No
server instances are configured ...` before Ray |

## How

- New `ConfigError` base in `config_types.py`;
`ConfigPathNotFoundError`, `MalformedConfigPathsError`,
`NoServerInstancesError` (and the existing `ServerRefNotFoundError`)
inherit it. They stay ordinary exceptions, so `ng_validate` (#1599,
`except Exception`) can still catch and format them.
- `load_extra_config_paths` wraps `OmegaConf.load` (#1488); `parse()`
wraps `ta.validate_python` (#1490).
- `raise_on_no_server_instances` (validated server-instance check, not a
raw key count) runs in **`RunHelper.start()`** before `initialize_ray()`
— covers both run and `e2e_rollout_collection` (#1489).
- A CLI decorator `exit_cleanly_on_config_error` converts any
`ConfigError` to a rich-escaped message + `exit 1`, **no traceback**.
Unexpected errors still propagate unchanged.

## Supersedes #1510

Consolidates [#1510](#1510):
typed exceptions `ng_validate` can catch/format (a bare `SystemExit`
would escape it), a validated zero-server check, the guard in `start()`
so `e2e` is covered, and deterministic tests.

## Tests

`test_global_config.py`: path-not-found (both-locations / dedup /
absolute), malformed config_paths, zero-server (raise + pass).
`test_cli.py`: the decorator (ConfigError → clean exit; non-ConfigError
propagates unchanged; success passes through). 67/67
`test_global_config`+`test_cli` pass; ruff + pre-commit clean.

---------

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
@wprazuch wprazuch force-pushed the wprazuch/ng-validate branch from 4ad73ce to a25ab3c Compare June 25, 2026 14:28
@wprazuch wprazuch changed the base branch from wprazuch/ng-test-concurrency to main June 25, 2026 14:28
@wprazuch wprazuch marked this pull request as ready for review June 25, 2026 14:28
@wprazuch wprazuch requested a review from a team as a code owner June 25, 2026 14:28
…ction #12 / FEP-1016)

Add `gym env validate` (+ ng_validate/nemo_gym_validate deprecated shims): run the full config parse
with no Ray and no server subprocesses, exit 0 (valid) / 1 (invalid) with a clean, traceback-free
message — config errors otherwise only surface ~30-60s later after Ray bootstrap. It reuses
get_global_config_dict so the checks stay in sync: config_paths resolution (#1488/#1490), server
cross-references (#1561), mandatory ??? values (#1575), and schema. A dummy policy_model (NO_MODEL)
is injected so model interpolations resolve without real creds — the model is supplied by --model*
at run time. Registered in the env group with the same config-selection flags as env start; wrapped
in exit_cleanly_on_config_error. Tests: env validate routing + validate() valid/invalid behavior.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
@wprazuch wprazuch force-pushed the wprazuch/ng-validate branch from a25ab3c to 82fb80c Compare June 25, 2026 14:31
Friction-point tracking belongs in the PR/epic, not in shipped docstrings.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
@ritaneves ritaneves linked an issue Jun 25, 2026 that may be closed by this pull request
1 task
@cmunley1

Copy link
Copy Markdown
Contributor

This double config flag seems strange to me, i get that we used to do a list, is there any other option? Hmm

gym env validate --config resources_servers/<env>/configs/<env>.yaml --config responses_api_models/<model>/configs/<model>.yaml

@ritaneves ritaneves linked an issue Jun 25, 2026 that may be closed by this pull request
1 task
@cmunley1

Copy link
Copy Markdown
Contributor

i guess another option could be

gym env validate --environment workplace_assistant --model-type openai_model

not sure what will be most common for development experience tho

@cmunley1

Copy link
Copy Markdown
Contributor

Given

A dummy policy_model is injected (the NO_MODEL parser config, as in gym list / env compose) so model interpolations like ${policy_base_url} resolve without real creds — validation is about config well-formedness; the real model is supplied by the --model* flags at run time.

Maybe dont need to even pass the model config here then?

chtruong814
chtruong814 previously approved these changes Jun 25, 2026
Comment thread nemo_gym/cli/env.py Outdated
cmunley1
cmunley1 previously approved these changes Jun 25, 2026

@cmunley1 cmunley1 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.

lgtm, just docs comment

Comment thread nemo_gym/cli/env.py Outdated
Comment thread tests/unit_tests/test_cli.py Outdated
…al tests)

@cmunley1 review:
- Examples now lead with `gym env validate --environment <env>` / `--benchmark <benchmark>`; reword
  so the model config is clearly optional (NO_MODEL injects a dummy policy_model).
- Remove the `# pragma: no cover` from validate() — it is unit-tested.
- Strengthen TestValidate to run REAL validation (valid config -> ok; unknown cross-ref -> clean
  exit 1) instead of mocking the parser; keep one fast decorator-path unit test.

The real test surfaced that ServerRefNotFoundError (a cross-ref error) was a plain ValueError, so it
escaped exit_cleanly_on_config_error and dumped a traceback. Fold it into the ConfigError family so
cross-reference errors are reported cleanly by validate (and gym env start).

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
@wprazuch wprazuch dismissed stale reviews from cmunley1 and chtruong814 via be03c9b June 25, 2026 15:25
@wprazuch wprazuch merged commit eed1942 into main Jun 25, 2026
16 checks passed
@wprazuch wprazuch deleted the wprazuch/ng-validate branch June 25, 2026 15:31
ritaneves pushed a commit that referenced this pull request Jun 25, 2026
…hs (#1205 #8/#12; #1488/#1489/#1490) (#1609)

## What

One coherent fix for the three `config_paths` failure modes, all failing
fast with a **clean message and no traceback**:

| Issue | Bad input | Before | After |
|-------|-----------|--------|-------|
| [#1488](#1488) | typo'd /
missing path | 7-frame `FileNotFoundError` | `Error: config_paths entry
'...' was not found. Looked in: ...` |
| [#1490](#1490) | scalar
instead of list | raw Pydantic `ValidationError` (+pydantic.dev URL) |
`Error: 'config_paths' must be a list of paths ...` |
| [#1489](#1489) | empty /
omitted (zero servers) | Ray starts, hangs until SIGTERM | `Error: No
server instances are configured ...` before Ray |

## How

- New `ConfigError` base in `config_types.py`;
`ConfigPathNotFoundError`, `MalformedConfigPathsError`,
`NoServerInstancesError` (and the existing `ServerRefNotFoundError`)
inherit it. They stay ordinary exceptions, so `ng_validate` (#1599,
`except Exception`) can still catch and format them.
- `load_extra_config_paths` wraps `OmegaConf.load` (#1488); `parse()`
wraps `ta.validate_python` (#1490).
- `raise_on_no_server_instances` (validated server-instance check, not a
raw key count) runs in **`RunHelper.start()`** before `initialize_ray()`
— covers both run and `e2e_rollout_collection` (#1489).
- A CLI decorator `exit_cleanly_on_config_error` converts any
`ConfigError` to a rich-escaped message + `exit 1`, **no traceback**.
Unexpected errors still propagate unchanged.

## Supersedes #1510

Consolidates [#1510](#1510):
typed exceptions `ng_validate` can catch/format (a bare `SystemExit`
would escape it), a validated zero-server check, the guard in `start()`
so `e2e` is covered, and deterministic tests.

## Tests

`test_global_config.py`: path-not-found (both-locations / dedup /
absolute), malformed config_paths, zero-server (raise + pass).
`test_cli.py`: the decorator (ConfigError → clean exit; non-ConfigError
propagates unchanged; success passes through). 67/67
`test_global_config`+`test_cli` pass; ruff + pre-commit clean.

---------

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
Signed-off-by: Rita Fernandes Neves <rfernandesne@nvidia.com>
wprazuch added a commit that referenced this pull request Jun 29, 2026
…CLI commands (#1754)

Documents the config/CLI features merged for epic #1205 that were not
yet reflected in the docs. Requested follow-up: a single doc PR covering
the recently merged config/CLI work.


## What's documented

| Area | Change | Merged in |
|---|---|---|
| `reference/cli-commands.mdx` | New `gym list environments`, `gym list
agents`, and `gym env validate` sections (+ Quick-Reference entries) |
#1635, #1671, #1599 |
| `troubleshooting/configuration.mdx` | Three `config_paths` startup
errors (Config Path Not Found, Malformed `config_paths`, No Server
Instances) + a `gym env validate` pre-flight tip; corrected the stale
`ServerRefNotFound` message | #1609, #1599 |
| `data/index.mdx` | Unified dataset `source:` block + dedicated
"Dataset `source`" subsection + legacy-deprecation note | #1637 |
| `data/download-huggingface.mdx` | Auto-download example migrated to
`source: { type: huggingface }` | #1637 |
| `reference/faq.mdx` | Dataset example and field bullets rewritten
around `source:` | #1637 |
| `environment-tutorials/single-step-environment.mdx` | Scaffold comment
updated to reference `source:` | #1637 |

---------

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
wprazuch added a commit that referenced this pull request Jun 29, 2026
Bring the gym env compose / config_composer work (RFC M3) up to date with main
(27 commits). Resolved overlapping CLI additions in nemo_gym/cli/main.py and
nemo_gym/cli/env.py: keep both the new `env compose` command (this branch) and
the `env validate` command (merged to main via #1599) as separate COMMANDS
entries and separate functions; both share the NO_MODEL parser-config pattern.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
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.

12 - Configuration Friction 3 - Configuration Friction

3 participants