Skip to content

fix(cli): report inference health from a served request - #8731

Open
laitingsheng wants to merge 12 commits into
mainfrom
fix/inference-health-truthfulness
Open

fix(cli): report inference health from a served request#8731
laitingsheng wants to merge 12 commits into
mainfrom
fix/inference-health-truthfulness

Conversation

@laitingsheng

@laitingsheng laitingsheng commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

nemoclaw <name> status reported inferenceHealth.ok: true and exited 0 while the in-sandbox inference route answered HTTP 401, and start exited 0 on the same route. The route probe reads any final HTTP 200-499 as reachable, so a rejected provider credential passed it. Status and start now send one inference request over the same route and report its result, so a rejected credential reports unauthorized and exits nonzero.

Related Issue

Fixes #8705

Changes

  • Rename src/lib/actions/sandbox/rebuild-inference-preflight.ts to inference-invocation-probe.ts and its exports to buildSandboxInferenceInvocationCommand and probeSandboxInferenceInvocation. The module already sent one minimal completion through inference.local on the sandbox's stored credential, but only Deep Agents Code rebuild preflight consumed it. Status and start are the second and third consumers, so the name now describes the behaviour rather than the first caller. The failure result adds httpStatus, and the timeout is a parameter: rebuild keeps 100 seconds, status and start use 30.
  • Compose inference health in src/lib/actions/sandbox/inference-route-health.ts. When the route probe reports the route reachable, status sends one inference request and its result drives inferenceHealth.ok; HTTP 401 or 403 sets failureLabel: "unauthorized". The route probe result becomes a route reachability subprobe so a failing verdict still shows that the route itself answered. A host-side upstream probe stays a diagnostic and does not change ok, keeping the sandbox route authoritative.
  • Gate startSandbox readiness on the same request inside verifyStarted, after the existing gateway and forward checks, and exit 1 when it fails. A sandbox with no recorded provider or model has nothing to request, so start skips it and exits 0.
  • Take the request's provider and model as one pair, preferring the live gateway route and falling back to the recorded route, so a partially readable live route cannot pair a live model with a recorded provider.
  • Update docs/reference/commands.mdx, including the Inference state table, and the pages whose acceptance criteria or failing-state lists this change invalidates: docs/inference/choose-local-inference-server.mdx, docs/inference/set-up-llama-cpp.mdx, docs/inference/set-up-ollama.mdx, docs/inference/set-up-vllm-on-two-dgx-stations.mdx, docs/deployment/deploy-to-headless-server.mdx, docs/monitoring/monitor-sandbox-activity.mdx, docs/reference/troubleshooting.mdx, and docs/security/credential-rotation.mdx.
  • Update the inference health entries in .agents/skills/_shared/controlled-words.md, which defined the term as the /v1/models classification alone.

Contract changes maintainers should weigh

  • This reverses part of nemoclaw status reports inference healthy on endpoint reachability, not model invocability — a green status can mask an unreachable model #6846. Two tests asserted the reported behaviour and are rewritten: the unit test expecting { ok: true, okLabel: "reachable" } beside a failed unauthorized subprobe, and the CLI test named "treats an inference.local HTTP %s as healthy", which asserted exit 0 for 401 and 403.
  • status and start now send a 16-token request through the stored provider credential on every run, so both wait up to 30 seconds for it and consume provider tokens on a hosted route.
  • doctor is unchanged and still classifies an HTTP 401 or 403 route response as reachable, so it exits 0 where status now reports unauthorized. The difference is documented; making doctor consistent needs its own change.
  • The issue also asks for phase to stop reporting Ready when inference is broken. phase is OpenShell's own container lifecycle value, parsed in src/lib/state/gateway.ts and shared with TERMINAL_SANDBOX_PHASES, so this change leaves it alone and reports the condition through inferenceHealth and the exit codes instead.
  • The serving-process gap in status inference health can only attest a fresh exec's environment, never the serving process's — surface process-level (self-reported) health #7003 remains open. The request runs in a fresh sandbox exec, so it attests the route and credential, not the long-running gateway process's own environment.

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)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification:
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: fix(cli): report inference health from a served request #8731 (comment)
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: docs-updated
  • Evidence: docs/reference/commands.mdx, docs/inference/choose-local-inference-server.mdx, docs/inference/set-up-llama-cpp.mdx, docs/inference/set-up-ollama.mdx, docs/inference/set-up-vllm-on-two-dgx-stations.mdx, docs/deployment/deploy-to-headless-server.mdx, docs/monitoring/monitor-sandbox-activity.mdx, docs/reference/troubleshooting.mdx, docs/security/credential-rotation.mdx, .agents/skills/_shared/controlled-words.md
  • Agent: Codex Desktop

DGX Station Hardware Evidence

  • Tested on DGX Station
  • Tested commit:
  • Station profile/scenario:
  • Result:
  • Supporting evidence:

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run validate:pr passed after refreshing origin/main when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result or justification: npx vitest run src/lib/actions/sandbox/status-snapshot-inference-health.test.ts src/lib/actions/sandbox/status-inference.test.ts src/lib/actions/sandbox/start.test.ts src/lib/actions/sandbox/inference-invocation-probe.test.ts src/lib/actions/sandbox/status-snapshot-recovery.test.ts — 5 files, 71 tests passed; npx vitest run test/cli — 35 files, 283 tests passed; the new CLI cases fail against a pre-fix build with expected +0 to be 1; follow-up rebuild harness validation passed 2 files and 9 tests after the probe rename; the runtime-recovery compatibility test and its related CLI suites passed 3 files and 29 tests after the fixture learned the agent-request probe
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result:
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run 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: Tinson Lai tinsonl@nvidia.com

Summary by CodeRabbit

  • New Features

    • Sandbox inference health checks now perform an actual inference request after route verification.
    • Status output distinguishes healthy, unauthorized, unreachable, unhealthy, reachable-only, and unverified results.
    • Sandbox startup validates inference readiness when provider and model details are available.
    • Diagnostics include request failures, HTTP status details, token usage, and authentication guidance.
  • Documentation

    • Updated deployment, setup, monitoring, troubleshooting, security, and command references to explain the new health-check behavior and statuses.

The in-sandbox route probe reads any final HTTP 200-499 as reachable, so a
rejected provider credential answered 401 while status reported healthy
inference and exited 0. Status and start now send one inference request over
the same route and report its result, and start exits nonzero when the
request fails.

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
@coderabbitai

coderabbitai Bot commented Aug 10, 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

Walkthrough

Sandbox inference health now combines route reachability with an authenticated inference request. Startup readiness, status output, failure labels, diagnostics, tests, and documentation now distinguish healthy, unauthorized, unreachable, and unhealthy results.

Changes

Sandbox inference health

Layer / File(s) Summary
Sandbox invocation probe API
src/lib/actions/sandbox/inference-invocation-probe.ts, src/lib/actions/sandbox/inference-invocation-probe.test.ts
Renames the probe API for sandbox inference invocation. Results now include HTTP status details and configurable timeouts.
Route-health composition
src/lib/actions/sandbox/inference-route-health.ts
Combines gateway reachability, invocation results, and provider diagnostics. Invocation failures receive structured labels such as unauthorized, unhealthy, and unreachable.
Status snapshot integration and coverage
src/lib/actions/sandbox/status-snapshot.ts, src/lib/actions/sandbox/status-inference.test.ts, src/lib/actions/sandbox/status-snapshot-inference-health.test.ts, src/lib/actions/sandbox/status-snapshot-recovery.test.ts
Status selects a provider/model pair, invokes the sandbox route after gateway checks, and preserves route and provider diagnostics as subprobes.
Startup and rebuild wiring
src/lib/actions/sandbox/start.ts, src/lib/actions/sandbox/start.test.ts, src/lib/actions/sandbox/rebuild-dcode-preflight.ts
Startup performs a timed inference request after gateway verification. Failed requests return a nonzero result. Rebuild checks use the shared invocation probe.
CLI status validation
test/cli/helpers.ts, test/cli/sandbox-status-json.test.ts, test/cli/sandbox-status-text.test.ts
Shared stubs now simulate inference responses. CLI tests cover healthy, unauthorized, reachable, and unprobed states.
Documentation and terminology
.agents/skills/_shared/controlled-words.md, docs/deployment/deploy-to-headless-server.mdx, docs/inference/*.mdx, docs/monitoring/monitor-sandbox-activity.mdx, docs/security/credential-rotation.mdx, docs/reference/commands.mdx, docs/reference/troubleshooting.mdx
Documentation defines inference health through route probing and an applicable inference request. Verification and troubleshooting guidance use the updated statuses.

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

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant statusSnapshot
  participant Gateway
  participant SandboxInference
  participant RouteHealth
  User->>statusSnapshot: request sandbox status
  statusSnapshot->>Gateway: probe inference route
  Gateway-->>statusSnapshot: route reachability
  statusSnapshot->>SandboxInference: send authenticated inference request
  SandboxInference-->>statusSnapshot: response and HTTP status
  statusSnapshot->>RouteHealth: combine route and invocation results
  RouteHealth-->>User: request-aware inference health
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR fixes inference health and start exit codes, but it leaves the lifecycle phase as Ready after inference failure, missing a key requirement in issue #8705. Update readiness or phase reporting so an unauthorized or failed inference request cannot leave the sandbox in phase Ready.
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The code, tests, and documentation changes directly support inference health, readiness checks, authorization failures, and the linked issue.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: inference health now reflects a served inference request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/inference-health-truthfulness

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

@laitingsheng laitingsheng added area: cli Command line interface, flags, terminal UX, or output area: inference Inference routing, serving, model selection, or outputs bug-fix PR fixes a bug or regression labels Aug 10, 2026
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — No blocking findings reported

Advisor assessment: No blocking advisor findings reported
Next action: No advisor follow-up needed.
Findings: 0 blockers · 0 warnings · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · medium confidence · 0 blockers · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · low confidence · 0 blockers · 4 warnings · 1 suggestion
  • Model comparison: normalized findings differ; normalized terminology decisions differ; normalized E2E selections differ; Nemotron reported the same number of blockers, 4 more warnings, 1 more suggestion.
4 terminology differences from the second opinion

Advisory only. These are normalized differences from the primary terminology receipt.

  • inference health at .agents/skills/_shared/controlled-words.md:187: primary classified it as established; the second opinion classified it as define.
  • healthy at .agents/skills/_shared/controlled-words.md:187: selected only by the second-opinion lane as define.
  • unauthorized at .agents/skills/_shared/controlled-words.md:187: selected only by the second-opinion lane as define.
  • reachable at .agents/skills/_shared/controlled-words.md:187: selected only by the second-opinion lane as replace.
2 additional E2E selections from the second opinion

Advisory only. The primary lane did not select these E2E jobs or targets.

  • hermes-inference-switch: The completed second-opinion lane identified E2E coverage that the primary lane omitted.
  • openclaw-inference-switch: The completed second-opinion lane identified E2E coverage that the primary lane omitted.

Second-opinion terminology and E2E selections are advisory. Live E2E does not run automatically for pull requests.

3 semantic terminology decisions

Terminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.

  • established — inference health at .agents/skills/_shared/controlled-words.md:187: Use inference health for the combined classification. Use inference route reachability for the /v1/models result alone.
  • established — route reachability at docs/reference/commands.mdx:1622: Use route reachability only for the /v1/models probe result. Do not use it to claim that an inference request succeeded.
  • justified — inference invocation probe at src/lib/actions/sandbox/inference-invocation-probe.ts:112: Keep the sandbox inference invocation modifier to distinguish this probe from the route-reachability probe.

E2E guidance

Advisory only. A maintainer can dispatch the default E2E suite for the commit under review.

Recommended E2E: managed-image-protected-runtime, inference-routing

Manual-only E2E: managed-image-multiarch-startup, network-policy, onboard-repair, onboard-resume, rebuild-openclaw, state-backup-restore, ubuntu-repo-docker-post-reboot-recovery
The manual PR workflow does not run these selectors for the commit under review. Run them from reviewed code on main.

1 optional E2E recommendation
  • ollama-auth-proxy

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

@copy-pr-bot

copy-pr-bot Bot commented Aug 10, 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.

@github-code-quality

github-code-quality Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in commit 2bf9536 in the fix/inference-health... branch remains at 96%, unchanged from commit de70924 in the main branch.

TypeScript / code-coverage/cli

The overall coverage in commit 2bf9536 in the fix/inference-health... branch remains at 82%, unchanged from commit de70924 in the main branch.

Show a code coverage summary of the most impacted files.
File main de70924 fix/inference-health... 2bf9536 +/-
src/lib/actions...ocker-health.ts 78% 61% -17%
src/lib/onboard...der/snapshot.ts 83% 75% -8%
src/lib/securit...ntial-filter.ts 95% 91% -4%
src/lib/onboard...press-resume.ts 81% 78% -3%
src/lib/inferen...ollama/proxy.ts 33% 36% +3%
src/lib/state/o...d-checkpoint.ts 85% 88% +3%
src/lib/trace.ts 90% 94% +4%
src/lib/cua/run...ime-manifest.ts 84% 91% +7%
src/lib/cua/bounded-file.ts 84% 94% +10%
src/lib/actions...cation-probe.ts 0% 95% +95%

Updated August 11, 2026 20:50 UTC

@github-actions

Copy link
Copy Markdown
Contributor

@apurvvkumaria apurvvkumaria self-assigned this Aug 11, 2026
@apurvvkumaria

Copy link
Copy Markdown
Collaborator

Maintainer decision required before readiness work continues

This PR changes the product contract in ways that need explicit maintainer direction:

  • Every status and applicable start call would send a live 16-token inference request, potentially adding provider cost and up to 30 seconds of latency.
  • It intentionally reverses part of nemoclaw status reports inference healthy on endpoint reachability, not model invocability — a green status can mask an unreachable model #6846 while leaving doctor with different health semantics.
  • The linked issue asks readiness not to remain Ready when inference is broken, but this PR leaves the OpenShell lifecycle phase unchanged. Accepting that split requires a scope and acceptance decision.
  • The current advisor warning also identifies a correctness risk when live provider/model data is combined with a recorded API family; that needs remediation if the proposed contract is accepted.

The sensitive-path and documentation receipts must also be refreshed for the current branch revision after the direction is settled. I am deferring implementation, approval, and merge because resolving the contract requires product and architecture judgment.

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

Blocking correctness finding on latest PR commit 4a5cbca0d.

status-snapshot.ts now takes the provider/model pair from the usable live gateway route, but still passes sb?.preferredInferenceApi from the recorded sandbox into runSandboxInferenceInvocationProbe. When live route drift changes the API family, status can send the wrong request shape/endpoint and report an otherwise usable route as unhealthy.

Derive provider, model, and API family from one route authority. If the live route is selected, use its compatible API family; otherwise use the complete recorded route contract. Add a status regression where the recorded route is Responses-based and the live route requires Chat Completions, then assert the served request uses the live route's endpoint and reports healthy.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
@prekshivyas
prekshivyas dismissed their stale review August 11, 2026 18:36

Addressed by a4b22d8: live and recorded inference routes now keep provider/model/API coherent; 13 focused status-inference tests and the exact-head pre-push typecheck passed.

Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
@apurvvkumaria

Copy link
Copy Markdown
Collaborator

Security review completed for the current #8731 revision.

Scope:

  • the in-sandbox inference request used by status, start, and DCode rebuild preflight
  • live-versus-recorded route selection
  • command construction, credential handling, timeouts, failure classification, and test-harness updates

Result: no actionable security finding.

The request uses the fixed https://inference.local origin. Provider and model values are encoded as JSON and shell-quoted. The command does not include a host credential, and it retains only the HTTP status. Status and start use a bounded 30-second execution timeout. Rebuild retains its existing 100-second allowance. The live provider, model, and compatible API family now come from one route authority, which resolves the prior request-shape finding.

Validation on commit 0c6b9a6ad:

  • 9 affected rebuild integration tests passed
  • 36 inference-focused CLI tests passed
  • CLI build and both TypeScript checks passed
  • repository structure checks and commit hooks passed

Fresh repository CI is running. The prior review request is resolved by the contributor's two route-coherence commits. The follow-up harness commit repairs the module rename that caused the earlier CI shard failures.

Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
@apurvvkumaria

Copy link
Copy Markdown
Collaborator

The failed CLI recovery check was caused by its OpenShell fixture not answering the new inference invocation. Revision 282a38b updates that fixture without changing production behavior. Five source-test files passed 84 tests, and three CLI integration files passed 29 tests. The Station pair-preparation failure was unrelated to the inference changes and passed twice in isolation, so the new revision provides a safe fresh CI run. The signed commit is Verified.

@github-actions github-actions Bot added v0.0.108 Release target and removed v0.0.107 labels Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command line interface, flags, terminal UX, or output area: inference Inference routing, serving, model selection, or outputs bug-fix PR fixes a bug or regression v0.0.108 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DGX Spark][CLI&UX] inferenceHealth.ok reports true and phase Ready while inference returns HTTP 401 (false health/readiness)

4 participants