Skip to content

Add EnterpriseOps-Gym benchmark: resources server, benchmark registration, and per-turn telemetry agent - #2142

Open
mcuevas-nvidia wants to merge 17 commits into
mainfrom
mcuevas-nvidia-bench-integration-enterpriseops-signed
Open

Add EnterpriseOps-Gym benchmark: resources server, benchmark registration, and per-turn telemetry agent#2142
mcuevas-nvidia wants to merge 17 commits into
mainfrom
mcuevas-nvidia-bench-integration-enterpriseops-signed

Conversation

@mcuevas-nvidia

Copy link
Copy Markdown

Summary

This PR integrates ServiceNow's EnterpriseOps-Gym (EOG) into NeMo Gym: a 649-task benchmark of stateful, multi-step enterprise tool use across 8 domains (calendar, CSM, drive, email, HR, ITSM, teams, and cross-domain hybrid), where an agent operates 512 tools against live MCP servers backed by SQL databases and is scored on final database state. The integration is eval-complete and RL-ready (token-ID capture, fractional reward mode, and a validated GRPO rollout-collection recipe), with no changes to NeMo Gym core.

What's included (46 files)

Component Path What it does
Resources server resources_servers/enterpriseops_gym/ Seeds a per-session database on the external EOG MCP containers, proxies tool calls (catch-all /{tool_name} route, pooled aiohttp, per-session x-database-id), runs verifiers concurrently, cleans up idempotently (TTL janitor + delete-on-verify). Supports replica pools (gym_url_pools), per-domain metrics, per-tool latency capture, and a strict_verifiers fractional-reward mode for RL.
Verifier engine .../verifier_engine.py Line-for-line port of EOG's scoring semantics, pinned by golden fixtures generated from the original implementation (33 cases, byte-identical).
Task converter .../convert_tasks.py + benchmarks/enterpriseops/ Converts the public HF dataset (ServiceNow-AI/EnterpriseOps-Gym) to Responses-API task rows at prepare.py time; benchmark registered with prompt_config: null (pre-baked rows). Dataset files are not committed.
Per-turn telemetry agent responses_api_agents/turn_logging_agent/ SimpleAgent subclass with an identical loop that records per-turn timestamps, durations, input/output/cached/reasoning tokens, and tool names, attaching turns to the verify response. Generic — not EOG-specific.
Tests 44 total (42 + 2) Fully offline: a sqlite-backed stub MCP gym (tests/stub_gym.py) plus golden parity fixtures. No containers or network needed to run CI.
Docs PARITY.md, PERF.md, RLPILOT.md Full parity evidence, throughput study, and RL rollout-collection pilot (methodology + measured numbers below).

Verification logic

Each task carries verifier_metadata with a list of verifiers. database_state verifiers
run a SQL query against the session's final database state (via the gym containers'
/api/sql-runner), extract a value, and compare it to the expected value using EOG's
comparison semantics; response_check verifiers score the agent's final message with an
LLM judge (defaults to the policy model, temperature pinned to 0.0, matching EOG). The
public oracle split is 100% database_state (3,496/3,496 verifiers), so scoring there is
fully deterministic given a final DB state. Reward = 1.0 iff all (name-collapsed) verifiers
pass, matching the upstream leaderboard; strict_verifiers: true switches to
every-verifier-counts and a fractional strict_pass_rate for RL shaping.

Scoring fidelity (PARITY.md)

The port is validated bug-for-bug against the upstream harness, preserving its quirks (verifier name-collapse, unknown-gym skips, loose comparison semantics) for leaderboard comparability:

  • Unit level: golden fixtures generated by running the original EOG engine — byte-identical extraction/comparison behavior.
  • Task level: 12/12 identical outcomes and verifier structures on live containers.
  • Full split (649 tasks): port 16.4% vs native 16.8% macro (gpt-4.1-mini, temp 0); per-task agreement 90.4%, disagreements symmetric (McNemar exact p = 0.90).
  • k=5 × both harnesses (6,480 rollouts): Δ −0.23 ± 0.7 pp, per-task preference exactly 67:67.
  • Cross-stack replication (k=5 on dedicated vLLM, Nemotron 3 Nano): formally equivalent within ±2 pp (TOST, α = 0.05).

Performance (PERF.md)

Scale-tested end-to-end at five client concurrencies (c = 8, 16, 32, 64, 128) with a full
649-task pass per level per harness (10 passes, 4×H100 vLLM, identical endpoint): the port
completed 649/649 tasks at every level with zero retries, with success rates flat
across levels. At matched concurrency the port is 1.14–1.71× faster (largest at low
concurrency, nearest the native harness's documented defaults). The gap narrows by design:
both harnesses converge toward the same GPU throughput floor — and reaching it is the key
result. The port saturates the hardware at c=64; the native harness never reaches the
floor in the tested range and needs ~4× the client concurrency for equal throughput.

Net cost: a full-split eval is 1h27m of 4×H100 time (port) vs 4h40m at native's documented
settings — 3.2× GPU-hours. Mechanism: pooled connections, persistent MCP sessions, and
concurrent verifiers keep vLLM's continuous batch fed. (Since the gap is client dead time
relative to GPU service time, it is expected to widen on faster serving hardware, where
saturation demands even more effective concurrency.)

RL readiness (RLPILOT.md)

A config-only pilot (zero code changes) validated GRPO rollout collection end-to-end: 100% token-ID/logprob coverage via return_token_id_information, 15/20 task groups with mixed binary reward at k=8 (mean within-group std 0.341) on a curriculum selected from repeat-run data, plus a measured deployment-sizing guide (sequence-length distribution, memory budget, recommended node shapes).

How to run

# Start the stack (external EOG MCP containers must be running; see resources server README)
ng_run "+config_paths=[resources_servers/enterpriseops_gym/configs/enterpriseops_gym.yaml,responses_api_models/openai_model/configs/openai_model.yaml]" \
  "++enterpriseops_gym.resources_servers.enterpriseops_gym.seed_sql_root=/path/to/EnterpriseOps-Gym"

# Prepare the benchmark data (downloads the public HF dataset) and collect
ng_prepare_benchmark +benchmark_name=enterpriseops
ng_collect_rollouts +agent_name=enterpriseops_gym_simple_agent \
  +input_jsonl_fpath=benchmarks/enterpriseops/data/enterpriseops_oracle_benchmark.jsonl \
  +output_jsonl_fpath=results/enterpriseops.jsonl \
  +responses_create_params.temperature=0.0 +responses_create_params.max_output_tokens=16384

# Tests (offline, no containers needed)
gym env test --resources-server enterpriseops_gym
ng_test +entrypoint=responses_api_agents/turn_logging_agent

Validation on this exact branch state

  • 42/42 + 2/2 tests green after rebase onto current main
  • ruff check + ruff format --check clean; README environment table regenerated via scripts/update_env_list.py
  • Config stack boots via ng_run dry run
  • Live smoke on real MCP containers + gateway model: 5/5 rollouts completed across both agents, all verifiers scored, turn telemetry attached
  • All commits DCO signed-off

Contribution-guide compliance

Mapped to the environment /
benchmark guides:

  • Required files — all present: app.py, configs/*.yaml (valid domain: agent),
    tests/test_app.py (42 tests), data/example.jsonl (5 tasks),
    data/example_rollouts.jsonl (5 pre-generated rollouts against live containers; note
    these samples are CSM-domain, the benchmark's hardest — near-zero rewards on them are
    expected and consistent with the full-split CSM rate of ~4%), requirements.txt,
    README.md with licensing information.
  • Reward profiling — run on a closed model (gpt-4.1-mini: 16.4% macro) and an open
    thinking model (Nemotron 3 Nano, reasoning on: 22–25%), i.e. the instruct+thinking
    mixture the guide asks for. Scores sit inside the official leaderboard's published range
    (Qwen3-4B 13.6% … GPT-5-Mini 22.0%) with a coherent domain pattern (email easiest, CSM
    hardest, matching the leaderboard). This benchmark is legitimately hard — no public model
    reaches 30%.
  • Variance — k=5 repeat runs on both stacks; mean@5 resolves ±0.7 pp (< 1% as required).
    Calibration guidance for users is included in PARITY.md.
  • Failure-case analysis — performed extensively across parity, perf, and RL-pilot runs
    (documented in the three reports).
  • Original-repo reproduction — instead of reproducing a leaderboard model's published
    number (leaderboard models weren't available on our serving), we ran the original EOG
    harness side-by-side
    on identical models, containers, and endpoints: per-task agreement
    with symmetric disagreements (McNemar p = 0.90) and formal TOST equivalence within ±2 pp.
    This isolates harness fidelity even more directly; happy to additionally run a listed
    leaderboard model if reviewers want the published-number check.
  • Stacked PRs — per the development-setup guide, happy to restack this as layers
    (resources server + tests → benchmark registration → turn-logging agent → reports) if
    reviewers prefer; presented as one PR first since the layers are tightly coupled by the
    parity evidence.

Design decisions & notes for reviewers

  • Hand-rolled MCP client instead of the official SDK (rationale in mcp_client.py docstring): the SDK's transport is httpx-based (banned for async here), EOG needs session-level and per-call x-database-id headers, and half the surface is non-MCP REST (/api/seed-database etc.).
  • Upstream EOG quirks intentionally preserved and documented (PARITY.md §1) rather than fixed, to keep leaderboard comparability; strict_verifiers: true opts into every-verifier-counts scoring for RL.
  • turn_logging_agent is separable — it's a general-purpose agent; happy to split it into its own PR if preferred.
  • verified: false per convention for new resources servers.
  • External dependency: the benchmark requires the EOG Docker containers (from the upstream EOG repo) at eval time; unit tests do not.
  • Operational findings that affect large runs (MCP container fd leak ~5/task, upstream runner's silent task drops) are documented in PARITY.md §6; we plan to file these upstream against EOG.

Data provenance & licensing

EnterpriseOps-Gym is Apache 2.0 (code) with a public HF dataset (ServiceNow-AI/EnterpriseOps-Gym). This PR commits only: tool-schema snapshots captured from the public EOG containers (7 JSON files, 512 tools), 13 sample tasks derived from the EOG repo's task files, 5 example rollouts generated against live containers, one synthetic hybrid task hand-authored for tests (written with LLM assistance against live container schemas — disclosed per the synthetic-data guideline), and golden verifier fixtures generated by running the EOG engine. The full benchmark dataset is downloaded at prepare.py time and gitignored.

mcuevas-nvidia and others added 10 commits July 24, 2026 21:43
…er-turn telemetry

Adapts the ServiceNow EnterpriseOps-Gym benchmark (Apache 2.0; 8 enterprise
domains, external MCP gym servers, SQL verifiers over final DB state) to
NeMo Gym:

- resources_servers/enterpriseops_gym: per-rollout DB seeding (SQL content
  cache + per-gym seed semaphores), catch-all /{tool_name} MCP proxy with
  EOG-parity observations and per-tool latency capture, idempotent /verify
  with guaranteed DB deletion, TTL janitor for killed rollouts, replica
  pools (gym_url_pools) for horizontal MCP scale-out, and per-domain
  aggregate metrics (leaderboard-style macro average).
- verifier_engine.py is a line-for-line port of the upstream engine,
  preserving its quirks for score parity (verifier name-collapse where
  duplicate-named verifiers overwrite; loose comparison semantics; skipped
  unknown-gym verifiers), pinned by golden fixtures generated from the
  original implementation. strict_verifiers=true switches the reward to
  every-verifier-counts for RL shaping.
- convert_tasks.py / snapshot_tools.py convert EOG tasks (local or the
  ServiceNow-AI/EnterpriseOps-Gym HF dataset) into NeMo Gym JSONL, baking
  tool schemas from live tools/list snapshots with per-task gym-order
  merge semantics (hybrid parity).
- benchmarks/enterpriseops: oracle public split (649 tasks) with HF
  download and offline local fallbacks.
- responses_api_agents/turn_logging_agent: behaviorally identical
  simple_agent variant that records per-turn telemetry (timestamps,
  input/output/cached tokens, tool names) and attaches it to verify
  responses; export_eval_telemetry.py emits the eval team's 21-field
  per-turn JSONL schema.

Validated at full scale against the native harness on the same 649 tasks,
model, and containers: macro success 16.4-17.8% across three runs, 90-94%
per-task agreement, McNemar p>=0.21 (no detectable harness bias), and
100% identical collapsed-verifier scoring structure.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Consolidates the equivalence case vs the native harness: golden-fixture
unit parity, 12/12 live task parity, full-public-split single-run
comparisons (McNemar p>=0.21, 100% scoring-structure agreement), and the
k=5 interleaved variance experiment (6,480 rollouts): mean@5 macro
16.54+/-0.73 vs 16.76+/-0.99 (delta -0.23pp), per-task preference 67:67,
and a direction-free gateway serving-path effect (+3.49pp outcome-flip
excess, permutation p<0.002) attributed to Responses-vs-ChatCompletions
serving rather than either harness. Includes calibration guidance
(report mean@k; ~6.3% of outcomes flip on any rerun) and upstream-relevant
operational findings (container fd leak, silent task drops, resume mode).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Upstream #1682 made the MCP Python SDK a core dependency, but for
Gym-as-MCP-server (the inverse of this module's Gym-as-MCP-client role).
Records why the SDK client is not a fit here: httpx transport (banned for
high-concurrency async), session-level vs required per-call isolation
headers, non-MCP REST endpoints comprising half the surface, and frozen
upstream protocol version.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
…ed GPU

Full oracle-split sweep (649 tasks x 2 harnesses x c in {8,16,32,64,128})
on 4xH100 TP=4 serving Nemotron 3 Nano FP8 locally, both harnesses on the
identical chat-completions endpoint. The port is 1.14-1.71x faster at
matched concurrency (largest at realistic low-c settings), needs ~4x less
client concurrency for equal throughput, and saturates the hardware at
c=64 while native never reaches the throughput floor in the tested range.
Success rates identical within noise at every level. Mechanism: GPU batch
starvation from native's per-request connections, per-task handshakes,
and sequential verifiers (GPU 98% busy both sides, client CPU idle).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Treats the 4xH100 performance sweep as an independent k=5 replication on
dedicated vLLM serving (Nemotron 3 Nano FP8, both harnesses on one
endpoint). Confirms the serving-path attribution via its designed
falsification test (cross-harness trajectory excess 3.49 -> 1.57pp, 55%
-> 11% of the noise floor), establishes formal TOST equivalence within
+/-2pp at alpha=0.05 with direction-free residuals (112:106 task
preference, sign p=0.735), and adds a determinism calibration for
reasoning models (41% flaky tasks vs 20% non-reasoning; report mean@5).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Config-only GRPO readiness validation on the 4xH100 stack: token-ID
capture via return_token_id_information, curriculum selection from
repeat-run sweep data, and group-mixing results (15/20 binary-mixed
at k=8, mean group std 0.341). Documents the unshuffled-benchmark
+limit pitfall and operational notes for long collection runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Measured train-sequence lengths (exact from v3 token IDs, band-wide via
calibrated estimate): curriculum yield is 63% at a 32k cap vs 94% at
64k, which drives the shape ranking (B300/B200 single node > H200 >
2x8 H100 disaggregated > single 8x H100 > LoRA fallback). Includes
trainer memory budget, step-time model, node layout, and the
pre-registered proof-point run sketch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Generated by scripts/update_env_list.py; the turnlog overlay config gains
a metadata block (a no-op merge over the inherited server) so the table
generator can render its row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
Per the environment contribution guide: data/example_rollouts.jsonl
(5 pre-generated rollouts from example.jsonl against live containers)
and a licensing/data-provenance section in the server README.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Jul 25, 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.

mcuevas-nvidia and others added 2 commits July 26, 2026 22:13
Generated via gym dataset collate +mode=example_validation; CI's
should_validate_data gate requires it alongside example.jsonl and
example_rollouts.jsonl.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
…h-integration-enterpriseops

Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@github-actions github-actions Bot added the sla:triage-overdue Review assignment is over the one-business-day SLA label Jul 27, 2026
The five flagged strings in enterpriseops_gym/data/tools/drive.json are
example Google Drive document IDs from the upstream EOG container's tool
schemas (one is the sample spreadsheet ID from Google's own API docs),
not credentials. Baseline updated with detect-secrets 1.5.0 to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@mcuevas-nvidia
mcuevas-nvidia requested a review from a team as a code owner July 27, 2026 01:29
gym env test discovery only treats modules with a README.md as
testable; with fail_on_total_and_test_mismatch=true the missing README
failed CI's shared server-tests job (found 137 modules, tested 136).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@@ -0,0 +1,3436 @@
{

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.

can these long files be pulled from somewhere like huggingface instead of committed?

@cmunley1

Copy link
Copy Markdown
Contributor

/claude review

@github-actions github-actions Bot removed the sla:triage-overdue Review assignment is over the one-business-day SLA label Jul 27, 2026
@claude

claude Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

SHIP WITH CARE — no BLOCKERs. The verifier port and reward aggregation are the highest-risk surface here and they're the most carefully done part of the PR: EOG parity quirks (name-collapse, unknown-gym skips, loose comparisons) are documented and pinned by golden fixtures, strict_verifiers cleanly separates leaderboard-parity reward from RL reward, verify is idempotent and deletes DBs in a finally, the MCP client correctly routes all async HTTP through nemo_gym.server_utils.request() (no httpx, no ray.get()), and per-call x-database-id isolation is the right call over the SDK's session-level headers. No core changes, tests are fully offline, deps declared. Good work.

Two non-blocking findings, both inline:

  1. RISK (turn_logging_agent/app.py): the agent hardcodes bare /v1/responses where simple_agent uses url_path_for_request/url_path_for_run, dropping the /ng-rollout/<id> capture-correlation prefix. No-op when observability is off, so eval/reward and inline return_token_id_information are unaffected — but this agent's whole purpose is RL telemetry, which is where capture gets enabled. The docstring even claims step-for-step parity; this is the divergence.

  2. RISK (app.py verify): all([]) is True, so a fully empty or all-skipped verifier set scores reward 1.0. A gym_name/pool misconfig silently converts every task to a false pass — inflates eval macro-rates and feeds spurious positive reward into GRPO. Guard the strict path (bool(strict_passed) and all(...)) and at least log.warning on num_verifiers_scored == 0.

Neither blocks merge; #2 is the one I'd want resolved before this feeds a training run.

Comment on lines +119 to +124
model_response = await self.server_client.post(
server_name=self.config.model_server.name,
url_path="/v1/responses",
json=new_body,
cookies=model_server_cookies,
)

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.

RISK — drops the /ng-rollout/<id> capture-correlation prefix that simple_agent applies.

The docstring says this loop "mirrors simple_agent step for step... Keep it in sync," but it has already diverged here: simple_agent.responses() uses url_path_for_request("/v1/responses", request) (line 89) and simple_agent.run() uses url_path_for_run("/v1/responses", body) (line 190). This agent hardcodes bare /v1/responses at both sites (here and line 273).

WHAT BREAKS: when model-call capture / observability is enabled, url_path_for_* prefixes the outgoing call with /ng-rollout/<rollout_id> so the model server can key captured calls to the rollout. Without it, this agent's captured model calls carry no correlation id — the exact per-rollout observability that a telemetry agent exists to provide is silently lost.

BLAST RADIUS: only when observability is on (no-op prefix otherwise), so eval/reward and return_token_id_information (inline in the response body) are unaffected — RLPILOT numbers stand. But this agent targets RL rollout collection, which is where capture is most likely enabled.

FIX: url_path=self.url_path_for_request("/v1/responses", request) here, and self.url_path_for_run("/v1/responses", body) in run(). Nearly every contributed agent (browsecomp, critpt, cvdp, non_executing_simple, gymnasium…) uses these helpers.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

89ba342 for the correlation fix

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Both call sites now use url_path_for_request / url_path_for_run, matching simple_agent, with a regression test that drives the /ng-rollout//v1/responses route and asserts the prefix survives onto the model call.

Comment on lines +484 to +490
overall_success = all(v["passed"] for v in verification_results.values())
verifier_pass_rate = passed_verifiers / total_verifiers if total_verifiers > 0 else 0.0

# Strict scoring over every defined verifier (skipped verifiers count as failed).
strict_passed = [entry["result"].get("passed", False) for entry in all_verifier_results]
strict_success = all(strict_passed)
strict_pass_rate = sum(strict_passed) / len(strict_passed) if strict_passed else 0.0

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.

RISK — an empty or all-skipped verifier set scores reward 1.0.

all([]) is True, so:

  • If every verifier is skipped (all reference an unknown gym_name), verification_results is empty → overall_success = all([]) = True → parity reward 1.0.
  • If a task defines zero verifiers, strict_passed = []strict_success = all([]) = True → strict reward 1.0.

WHAT BREAKS: a misconfigured gym_url_pools/dataset gym_name mismatch (plausible when pointing at replicas for an RL run) silently turns every task into a false pass instead of a hard failure. That corrupts eval macro-rates upward and injects spurious positive reward into GRPO training — the worst-case silent-corruption path.

Note the skipped-verifier→fail guarantee already holds for strict mode when some verifiers survive (test_tool_execution_verifier_and_skipped_gym); the gap is only the fully-empty set.

FIX (at minimum for the strict/RL path, where empty=pass is never intended):
strict_success = bool(strict_passed) and all(strict_passed).
For the parity path, confirm upstream EOG also awards 1.0 on an all-skipped task; if it does, keep it but consider a log.warning when num_verifiers_scored == 0 so silent all-skips are visible in large runs.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

b0494d2 for the verifier guard

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed for the strict/RL path in b0494d2 (bool(strict_passed) and all(strict_passed)), with a regression test.

The collapsed metric keeps upstream EOG's all([]) behavior on purpose: that path is a bug-for-bug port of the upstream scorer, which is what keeps our numbers comparable to the published EOG leaderboard. The rationale is documented at the code site, and num_verifiers_scored exposes the empty-set case to callers.

mcuevas-nvidia and others added 2 commits July 28, 2026 18:13
Mirror simple_agent's url_path_for_request/url_path_for_run so
/ng-rollout/<id>-prefixed self-calls keep per-rollout observability
correlation on downstream model calls. Adds a regression test driving
the prefixed route. Addresses PR #2142 review feedback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
all([]) is True, so a task with zero scorable verifiers awarded
strict reward 1.0. Guard the strict path (which feeds RL rewards);
the collapsed parity path intentionally keeps upstream's all([])
semantics for leaderboard comparability, now documented in place.
Addresses PR #2142 review feedback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@mcuevas-nvidia

mcuevas-nvidia commented Jul 28, 2026 via email

Copy link
Copy Markdown
Author

…h-integration-enterpriseops

Signed-off-by: Marc Cuevas <mcuevas@nvidia.com>
@ritaneves
ritaneves requested a review from Glorf July 30, 2026 08:24
@github-actions github-actions Bot added the sla:review-overdue Review response is over the one-business-day SLA label Jul 31, 2026
@ritaneves
ritaneves removed the request for review from Glorf August 7, 2026 10:44
@github-actions github-actions Bot removed the sla:review-overdue Review response is over the one-business-day SLA label Aug 7, 2026
@ritaneves
ritaneves requested a review from bxyu-nvidia August 8, 2026 08:52
@github-actions github-actions Bot added the sla:review-overdue Review response is over the one-business-day SLA label Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sla:review-overdue Review response is over the one-business-day SLA

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants