Skip to content

test(e2e): add model router routed guard for #3255 - #3601

Merged
cv merged 9 commits into
mainfrom
pr-3594-rebased-main
May 15, 2026
Merged

test(e2e): add model router routed guard for #3255#3601
cv merged 9 commits into
mainfrom
pr-3594-rebased-main

Conversation

@jyaunches

@jyaunches jyaunches commented May 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a regression E2E guard for model-router provider-routed inference so the routed inference path is covered in the regression workflow. This replaces closed PR #3594 from the rebased branch because repository rules blocked force-pushing the original PR branch.

Related Issue

Refs #3255

Changes

  • Adds test/e2e/test-model-router-provider-routed-inference.sh for provider-routed inference coverage.
  • Updates .github/workflows/regression-e2e.yaml to include the new regression guard.
  • Updates E2E parity metadata in test/e2e/docs/parity-map.yaml and test/e2e/docs/parity-inventory.generated.json.
  • Carries the rebased compatibility cleanup currently present on pr-3594-rebased-main.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Verification

  • npx prek run --all-files passes
  • npm test passes
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • make docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Julie Yaunches jyaunches@nvidia.com

Summary by CodeRabbit

  • Tests

    • Added an end-to-end coverage guard that verifies provider-routed Model Router onboarding and routed completions, including health checks, routed response validation, redacted log capture, and failure reporting.
  • Chores

    • CI regression workflow updated to include a selectable job for the new E2E guard and conditionally run it; model-router-specific artifacts are uploaded on failures.
  • Documentation

    • Test inventory and mapping updated to include the new script, assertions, and revised totals.

Review Change Stack

jyaunches added 3 commits May 15, 2026 12:24
Adds a failing E2E test that demonstrates the bug tracked by #3255.

Until the fix lands, the regression-e2e model-router-provider-routed-inference-e2e job will fail. This is intentional: the failing test is the executable acceptance criterion.

Related: #3255
@jyaunches jyaunches self-assigned this May 15, 2026
@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor

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

Walkthrough

Adds a new E2E regression test (issue #3255) that verifies Model Router provider-routed inference; extends the regression workflow to select and gate the job; implements a bash test that validates prerequisites, onboards a sandbox, polls Model Router health, verifies routed completions, redacts logs, and updates parity docs.

Changes

Model Router provider-routed inference E2E regression test

Layer / File(s) Summary
Workflow dispatch and job selection
.github/workflows/regression-e2e.yaml
Extended workflow_dispatch valid jobs to include model-router-provider-routed-inference-e2e, added select_regression_jobs output model_router_provider_routed_inference, selection logic, and a gated job that runs the test script and uploads logs on failure.
Test script header and helpers
test/e2e/test-model-router-provider-routed-inference.sh
Script header, strict mode, counters, structured output helpers, and is_routed_pong_response JSON parser validating model matches nvidia-routed and first choice contains PONG.
Log redaction, cleanup, and NemoClaw install
test/e2e/test-model-router-provider-routed-inference.sh
Redaction helpers, cleanup EXIT trap that redacts logs and destroys sandbox unless kept, Docker and NVIDIA_API_KEY prerequisite checks, and logic to install nemoclaw from checkout when missing.
Sandbox onboarding and health polling
test/e2e/test-model-router-provider-routed-inference.sh
Performs fresh sandbox onboarding configured for provider-routed inference, captures/redacts onboarding logs, polls /health until at least one healthy endpoint.
Inference polling and test summary
test/e2e/test-model-router-provider-routed-inference.sh
Attempts routed inference.local chat completions from inside sandbox, writes/redacts responses, detects routed PONG success or failure patterns, and exits 0 only on success.
Parity map and inventory documentation
test/e2e/docs/parity-inventory.generated.json, test/e2e/docs/parity-map.yaml
Adds new entrypoint and scenario for the test script with assertion records and updates totals.assertions and totals.scripts.

Sequence Diagram(s)

sequenceDiagram
  participant User as workflow_dispatch
  participant Selector as select_regression_jobs
  participant CIJob as model-router-provider-routed-inference-e2e
  participant Sandbox as Sandbox
  participant ModelRouter as Model Router
  User->>Selector: submit jobs input
  Selector->>CIJob: enable job when selected
  CIJob->>Sandbox: run test script (onboard sandbox, call endpoints)
  Sandbox->>ModelRouter: poll /health & /v1/chat/completions
  ModelRouter-->>Sandbox: health status, routed completion responses
  CIJob->>CIJob: upload logs on failure
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#3411: Both PRs modify .github/workflows/regression-e2e.yaml to extend the workflow_dispatch job-selection (select_regression_jobs + conditional regression job gating), with the retrieved PR adding gateway-health-honest-e2e and the main PR adding model-router-provider-routed-inference-e2e.

Suggested labels

enhancement: testing, E2E

Suggested reviewers

  • ericksoa

Poem

🐰 I hop the sandbox, key redacted tight,
I poll the health through day and night,
I wait for PONG from routed land,
Logs scrubbed clean by careful hand,
A joyful hop — the test took flight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% 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 clearly identifies the main change: adding a model router routed inference guard test for issue #3255.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr-3594-rebased-main

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

Comment thread test/e2e/test-model-router-provider-routed-inference.sh
Comment thread test/e2e/test-model-router-provider-routed-inference.sh
Comment thread test/e2e/test-model-router-provider-routed-inference.sh
Comment thread test/e2e/test-model-router-provider-routed-inference.sh
Comment thread test/e2e/test-model-router-provider-routed-inference.sh
Comment thread test/e2e/test-model-router-provider-routed-inference.sh
Comment thread test/e2e/test-model-router-provider-routed-inference.sh
Comment thread test/e2e/test-model-router-provider-routed-inference.sh
Comment thread test/e2e/test-model-router-provider-routed-inference.sh
@github-actions

github-actions Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: None
Optional E2E: model-router-provider-routed-inference-e2e

Dispatch hint: model-router-provider-routed-inference-e2e

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • None. No required product E2E is recommended because this PR only changes E2E workflow/test assets and parity documentation; it does not modify installer, onboarding, sandbox lifecycle, credentials, security policy, network policy, or runtime inference implementation code.

Optional E2E

  • model-router-provider-routed-inference-e2e (high; requires Docker, OpenShell/NemoClaw install/onboard, sandbox lifecycle, and NVIDIA_API_KEY-backed external inference): Optional validation of the newly added regression job and script wiring. It directly exercises the new Model Router provider-routed inference guard added by this PR, but product runtime code is not changed, so it should not be merge-blocking.

New E2E recommendations

  • None.

Dispatch hint

  • Workflow: .github/workflows/regression-e2e.yaml
  • jobs input: model-router-provider-routed-inference-e2e

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/e2e/test-model-router-provider-routed-inference.sh`:
- Around line 19-36: is_routed_pong_response fails because the embedded Python
reads sys.stdin.read() while the here-doc (python3 - <<'PY') consumes stdin, so
the JSON payload passed via here-string is empty; fix by changing the function
to accept the payload as an argument and invoke Python so it reads from sys.argv
(not stdin): replace the here-doc usage in is_routed_pong_response with a Python
invocation that reads the payload from sys.argv[1] (or similar), and update
callers to call is_routed_pong_response "$response" instead of piping via stdin.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c5abdae9-fdc4-4efe-9fe8-55fc82c1c40a

📥 Commits

Reviewing files that changed from the base of the PR and between da1ad74 and b4ab815.

📒 Files selected for processing (4)
  • .github/workflows/regression-e2e.yaml
  • test/e2e/docs/parity-inventory.generated.json
  • test/e2e/docs/parity-map.yaml
  • test/e2e/test-model-router-provider-routed-inference.sh

Comment thread test/e2e/test-model-router-provider-routed-inference.sh

@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)
test/e2e/test-model-router-provider-routed-inference.sh (1)

19-36: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Pass the response payload via argv instead of stdin.

python3 - <<'PY' consumes stdin for the here-doc itself, so sys.stdin.read() is empty when this function is called with <<<"$response". That makes the routed-response check fail even for valid JSON and turns this regression guard into a false negative.

🔧 Minimal fix
 is_routed_pong_response() {
-  python3 - <<'PY'
+  local raw="$1"
+  python3 - "$raw" <<'PY'
 import json, re, sys
-raw = sys.stdin.read()
+raw = sys.argv[1]
 try:
     data = json.loads(raw)
 except Exception:
     raise SystemExit(1)
@@
-  if is_routed_pong_response <<<"$response"; then
+  if is_routed_pong_response "$response"; then
@@
-if is_routed_pong_response <<<"$response"; then
+if is_routed_pong_response "$response"; then

You can verify the shell/Python stdin behavior with:

#!/bin/bash
set -euo pipefail

sed -n '19,36p;161p;171p' test/e2e/test-model-router-provider-routed-inference.sh

bash -c '
f() {
  python3 - <<'"'"'PY'"'"'
import sys
print(len(sys.stdin.read()))
PY
}
f <<<"abc"
'

Expected result: the demo prints 0, confirming the here-doc, not the here-string payload, reaches Python stdin.

Also applies to: 161-161, 171-171

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/test-model-router-provider-routed-inference.sh` around lines 19 -
36, The is_routed_pong_response bash helper consumes the response via a here-doc
which prevents the caller's here-string (<<<"$response") from reaching Python's
stdin, causing false negatives; update the Python invocation inside
is_routed_pong_response to accept the JSON payload as an argv parameter (e.g.,
read from sys.argv[1]) instead of sys.stdin.read(), and adjust any other similar
helpers called at lines referenced (around 161 and 171) so they also pass the
response via argv; locate the Python block inside is_routed_pong_response and
change the input code path from sys.stdin.read() to using sys.argv[1] (or
equivalent) and ensure the bash call forwards "$response" as an argument.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@test/e2e/test-model-router-provider-routed-inference.sh`:
- Around line 19-36: The is_routed_pong_response bash helper consumes the
response via a here-doc which prevents the caller's here-string (<<<"$response")
from reaching Python's stdin, causing false negatives; update the Python
invocation inside is_routed_pong_response to accept the JSON payload as an argv
parameter (e.g., read from sys.argv[1]) instead of sys.stdin.read(), and adjust
any other similar helpers called at lines referenced (around 161 and 171) so
they also pass the response via argv; locate the Python block inside
is_routed_pong_response and change the input code path from sys.stdin.read() to
using sys.argv[1] (or equivalent) and ensure the bash call forwards "$response"
as an argument.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: dd37f849-8064-4b16-a1f8-9097b4b42104

📥 Commits

Reviewing files that changed from the base of the PR and between 960048b and 0a72804.

📒 Files selected for processing (2)
  • test/e2e/docs/parity-inventory.generated.json
  • test/e2e/test-model-router-provider-routed-inference.sh
✅ Files skipped from review due to trivial changes (1)
  • test/e2e/docs/parity-inventory.generated.json

@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)
test/e2e/test-model-router-provider-routed-inference.sh (1)

30-47: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix routed-response parsing: stdin is consumed by the heredoc, so valid responses are never detected.

At Line 31, python3 - <<'PY' feeds the script through stdin; then Line 33 reads stdin for JSON, which is empty. With current call sites on Line 172 and Line 182, is_routed_pong_response will consistently fail parsing.

Suggested minimal fix
 is_routed_pong_response() {
-  python3 - <<'PY'
+  local raw="$1"
+  python3 - "$raw" <<'PY'
 import json, re, sys
-raw = sys.stdin.read()
+raw = sys.argv[1]
 try:
     data = json.loads(raw)
 except Exception:
     raise SystemExit(1)
@@
 raise SystemExit(0 if ok_model and ok_content else 1)
 PY
 }
@@
-  if is_routed_pong_response <<<"$response"; then
+  if is_routed_pong_response "$response"; then
@@
-if is_routed_pong_response <<<"$response"; then
+if is_routed_pong_response "$response"; then
#!/usr/bin/env bash
set -euo pipefail

# Verify the stdin/heredoc behavior causing the failure.
broken() {
  python3 - <<'PY'
import sys
print(len(sys.stdin.read()))
PY
}
echo "broken (expected 0): $(broken <<< 'abc')"

fixed() {
  local raw="$1"
  python3 - "$raw" <<'PY'
import sys
print(len(sys.argv[1]))
PY
}
echo "fixed (expected 3): $(fixed 'abc')"

Also applies to: 172-172, 182-182

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/test-model-router-provider-routed-inference.sh` around lines 30 -
47, The is_routed_pong_response helper is reading JSON from stdin but the
heredoc used to invoke python consumes stdin so the script always sees empty
input; fix by passing the raw response into Python as an argument (or env var)
instead of relying on sys.stdin: change the bash wrapper that defines
is_routed_pong_response to capture the heredoc into a shell variable (e.g., raw)
and invoke python with that value as an argument, then update the Python code
inside is_routed_pong_response to parse sys.argv[1] (or the env var) for the
JSON and keep the existing model/choices/content checks; also update the places
that call is_routed_pong_response to pass the response string rather than
relying on stdin.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@test/e2e/test-model-router-provider-routed-inference.sh`:
- Around line 30-47: The is_routed_pong_response helper is reading JSON from
stdin but the heredoc used to invoke python consumes stdin so the script always
sees empty input; fix by passing the raw response into Python as an argument (or
env var) instead of relying on sys.stdin: change the bash wrapper that defines
is_routed_pong_response to capture the heredoc into a shell variable (e.g., raw)
and invoke python with that value as an argument, then update the Python code
inside is_routed_pong_response to parse sys.argv[1] (or the env var) for the
JSON and keep the existing model/choices/content checks; also update the places
that call is_routed_pong_response to pass the response string rather than
relying on stdin.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 48ab1c12-a672-414c-81f0-9f0381cf49fe

📥 Commits

Reviewing files that changed from the base of the PR and between 0a72804 and 530ac9d.

📒 Files selected for processing (1)
  • test/e2e/test-model-router-provider-routed-inference.sh

@cv
cv merged commit 85804e9 into main May 15, 2026
24 checks passed
@wscurran wscurran added the chore Build, CI, dependency, or tooling maintenance label Jun 8, 2026
@jyaunches
jyaunches deleted the pr-3594-rebased-main branch June 12, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Build, CI, dependency, or tooling maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants