Skip to content

fix(rebuild): persist inference selection metadata - #5869

Merged
jyaunches merged 12 commits into
mainfrom
fix/rebuild-inference-selection-metadata
Jun 26, 2026
Merged

fix(rebuild): persist inference selection metadata#5869
jyaunches merged 12 commits into
mainfrom
fix/rebuild-inference-selection-metadata

Conversation

@jyaunches

@jyaunches jyaunches commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a shared inference selection metadata shape and persist endpoint/credential/API metadata on sandbox registry entries.
  • Use durable registry metadata during rebuild recovery so custom compatible endpoints can be recreated even when the global onboard session belongs to another sandbox.
  • Keep inference-set registry updates in sync with the expanded metadata.

Why

This addresses the double-onboard-e2e stale rebuild recovery failure where e2e-double-a is preserved only in the registry after direct OpenShell deletion, while the active onboard session belongs to e2e-double-b. Rebuild must not borrow endpoint data from the unrelated session, but now has the target sandbox endpoint metadata durably recorded.

Validation

  • npm run build:cli
  • npm test -- src/lib/actions/sandbox/rebuild-resume-config.test.ts src/lib/onboard/sandbox-registration.test.ts test/registry.test.ts src/lib/actions/inference-set.test.ts

Note: pre-push full test hook timed out/failed in unrelated environment setup tests (missing nemoclaw/node_modules/json5 and multiple spawned CLI timeouts), after the focused validation above passed.

Summary by CodeRabbit

  • New Features
    • Sandbox setup, rebuild, and resume flows now persist and restore richer inference settings, including endpoint URL, credential environment, preferred inference API, and container details.
    • Rebuild-on-resume can now use durable saved registry metadata to reconstitute custom endpoint information more reliably.
  • Bug Fixes
    • Improved consistency of inference metadata during sandbox registry updates, provider/model switches, and resume/rebuild recovery.
    • More accurate built-in messaging channel availability detection based on manifest completeness.
  • Tests
    • Expanded unit and live E2E coverage to validate persisted inference metadata and updated registry/session behaviors.

@coderabbitai

coderabbitai Bot commented Jun 26, 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

The PR normalizes inference-selection metadata, persists it through sandbox registration and rebuild flows, updates inference-set registry writes, and changes messaging channel availability lookup.

Changes

Inference selection metadata propagation

Layer / File(s) Summary
Selection shape and registry persistence
src/lib/inference/selection.ts, src/lib/state/registry.ts, test/registry.test.ts
Defines normalized inference-selection fields, extends sandbox registry entries with those fields, persists them to sandboxes.json, and updates the registry persistence test.
Sandbox creation registration
src/lib/onboard.ts, src/lib/onboard/sandbox-registration.ts, src/lib/onboard/machine/handlers/sandbox.ts, src/lib/onboard/sandbox-registration.test.ts, test/e2e-scenario/live/openclaw-inference-switch.test.ts, test/e2e-scenario/live/rebuild-hermes.test.ts
Loads the persisted session into inferenceSelection, passes it into created-sandbox registration, writes nimContainer and preferredInferenceApi during sandbox handling, and updates the creation-path tests and live scenario assertions.
Rebuild resume selection
src/lib/actions/sandbox/rebuild-resume-config.ts, src/lib/actions/sandbox/rebuild-resume-config.test.ts, src/lib/actions/sandbox/rebuild.ts, test/e2e-scenario/live/double-onboard.test.ts
Derives rebuild inputs from normalized registry selection data, accepts recorded endpoint and credential metadata, adds preferredInferenceApi to the resume config, and pins it during rebuild.
Inference-set registry update
src/lib/actions/inference-set.ts, src/lib/actions/inference-set.test.ts
Writes the richer inference-selection fields into sandbox updates during runInferenceSet and loosens the test matchers to assert the expanded registry payloads.

Messaging channel availability context

Layer / File(s) Summary
Messaging channel availability lookup
src/lib/onboard/messaging-channel-setup.ts
detectMessagingChannelsFromEnv now passes the built-in manifest registry list into the availability context helper.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#5787: Rebuild and resume-config changes here touch the same sandbox recreate flow and recorded-metadata handling.
  • NVIDIA/NemoClaw#5831: This PR changes preflightRebuildCredentials in src/lib/actions/sandbox/rebuild.ts, which is the same rebuild preflight path affected here.
  • NVIDIA/NemoClaw#5788: Both PRs touch detectMessagingChannelsFromEnv in src/lib/onboard/messaging-channel-setup.ts.

Suggested labels

refactor, area: onboarding

Suggested reviewers

  • sandl99
  • ericksoa

Poem

A rabbit hopped through registry dew,
With endpoint crumbs and metadata true.
I tucked preferredInferenceApi in my sack,
And bounced the rebuild path right back.
🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% 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 is concise and accurately captures the main change: persisting inference selection metadata for rebuild-related flows.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rebuild-inference-selection-metadata

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

@github-code-quality

github-code-quality Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the fix/rebuild-inferenc... branch is 96%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main fix/rebuild-inferenc... 07b38f3 +/-
nemoclaw/src/se...cret-scanner.ts 100%
nemoclaw/src/commands/slash.ts 100%
nemoclaw/src/li...bprocess-env.ts 100%
nemoclaw/src/bl...eprint/state.ts 98%
nemoclaw/src/onboard/config.ts 98%
nemoclaw/src/bl...int/snapshot.ts 97%
nemoclaw/src/bl...print/runner.ts 95%
nemoclaw/src/co...ration-state.ts 94%
nemoclaw/src/bl...ate-networks.ts 94%
nemoclaw/src/index.ts 94%

TypeScript / code-coverage/cli

The overall coverage in the fix/rebuild-inferenc... branch is 47%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main fix/rebuild-inferenc... 07b38f3 +/-
src/lib/state/o...oard-session.ts 91%
src/lib/actions...dbox/rebuild.ts 73%
src/lib/sandbox/config.ts 72%
src/lib/onboard/preflight.ts 62%
src/lib/shields/index.ts 62%
src/lib/actions...licy-channel.ts 60%
src/lib/state/sandbox.ts 56%
src/lib/policy/index.ts 48%
src/lib/onboard...er-gpu-patch.ts 47%
src/lib/onboard.ts 19%

Updated June 26, 2026 17:24 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

Comment thread src/lib/actions/inference-set.test.ts Fixed
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: onboard-resume-e2e, onboard-repair-e2e, cloud-onboard-e2e, openclaw-inference-switch-e2e, openclaw-anthropic-inference-switch-e2e, hermes-inference-switch-e2e, hermes-anthropic-inference-switch-e2e, inference-routing-e2e, rebuild-openclaw-e2e, rebuild-hermes-e2e, double-onboard-e2e, messaging-compatible-endpoint-e2e
Optional E2E: rebuild-hermes-stale-base-e2e, sandbox-operations-e2e

Dispatch hint: onboard-resume-e2e,onboard-repair-e2e,cloud-onboard-e2e,openclaw-inference-switch-e2e,openclaw-anthropic-inference-switch-e2e,hermes-inference-switch-e2e,hermes-anthropic-inference-switch-e2e,inference-routing-e2e,rebuild-openclaw-e2e,rebuild-hermes-e2e,double-onboard-e2e,messaging-compatible-endpoint-e2e

Auto-dispatched E2E: onboard-resume-e2e, double-onboard-e2e, messaging-compatible-endpoint-e2e via nightly-e2e.yaml at 07b38f350fb14c657b02d5ae23c2afda41e276ffnightly run

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • onboard-resume-e2e (medium): Required by the onboarding resume compatibility rule: the PR changes sandbox live-slice orchestration/registry updates in src/lib/onboard/machine/handlers/sandbox.ts and persisted onboarding state used by resume.
  • onboard-repair-e2e (medium): Required by the onboarding resume compatibility rule: repair must cover changed resume/registry/session semantics and custom endpoint metadata handling, not just unit/runtime-boundary tests.
  • cloud-onboard-e2e (high): Full hosted onboarding can be affected because createSandbox/registerCreatedSandbox now persists inference selection metadata and preferredInferenceApi into registry entries after a real sandbox becomes ready.
  • openclaw-inference-switch-e2e (medium): runInferenceSet and OpenClaw config patching/registry update ordering changed; this E2E verifies switching a live OpenClaw sandbox, registry state, in-sandbox config, hashes, and live requests.
  • openclaw-anthropic-inference-switch-e2e (medium): The PR specifically changes preferredInferenceApi and durable metadata behavior for compatible-anthropic endpoints; this covers OpenClaw Anthropic Messages switching with the live switch path.
  • hermes-inference-switch-e2e (medium): runInferenceSet changes also affect Hermes config.yaml, registry metadata, and session updates; this E2E validates live Hermes inference switching and hash/config consistency.
  • hermes-anthropic-inference-switch-e2e (medium): The Hermes Anthropic-compatible path depends on preferredInferenceApi and endpoint/credential metadata preserved by this PR; this should gate changes to compatible-anthropic switching.
  • inference-routing-e2e (medium): Shared inference selection normalization and registry fields can affect provider/model/endpoint routing and validation; this covers hosted inference routing behavior end to end.
  • rebuild-openclaw-e2e (high): rebuild-resume-config and rebuild.ts changed the pre-delete recreate trust boundary and session rewrite. OpenClaw rebuild should gate registry-derived provider/model/credential/endpoint replay.
  • rebuild-hermes-e2e (high): Hermes rebuild is directly touched by changed live scenario tests and by preferredInferenceApi/session rewrite changes; it should verify real Hermes recreate behavior from registry metadata.
  • double-onboard-e2e (medium): The PR changes sandbox registration and avoids borrowing metadata from unrelated sessions; double-onboard exercises consecutive real onboarding sessions and catches cross-session registry/session contamination.
  • messaging-compatible-endpoint-e2e (medium): Custom-compatible endpoint metadata is now durable and trusted for recreate/switch paths. This existing E2E validates OpenAI-compatible endpoint routing through inference.local with a hermetic local mock and real assistant flow.

Optional E2E

  • rebuild-hermes-stale-base-e2e (high): Useful adjacent confidence for the changed rebuild-hermes scenario when the base image is stale, but the main rebuild-hermes-e2e covers the required Hermes rebuild path.
  • sandbox-operations-e2e (medium): Optional broad sandbox lifecycle coverage for registry shape changes, default sandbox behavior, and operations that read SandboxEntry metadata.

New E2E recommendations

  • custom compatible endpoint rebuild from durable registry metadata (high): Existing rebuild E2Es cover general rebuild flows, but this PR introduces a specific trust boundary: a custom OpenAI/Anthropic-compatible sandbox with endpointUrl/credentialEnv/preferredInferenceApi in the registry should rebuild from a non-matching current session without borrowing unrelated endpoint data, and should fail closed when durable endpoint metadata is malformed or absent.
    • Suggested test: Add a live rebuild scenario for compatible-endpoint and compatible-anthropic-endpoint sandboxes that creates one sandbox, loads an unrelated onboard session, then runs rebuild and verifies the recreated sandbox uses only the target registry endpoint/API metadata.
  • inference set custom-compatible provider switch guard (medium): runInferenceSet now rejects switching to compatible-endpoint or compatible-anthropic-endpoint without trusted durable endpoint metadata. Unit tests cover the exception, but a CLI-level E2E would verify no gateway/registry mutation occurs after the failed command.
    • Suggested test: Add an E2E case to the inference-switch scenarios that attempts nemoclaw inference set --provider compatible-endpoint without matching durable endpoint metadata and asserts failure plus unchanged gateway route and registry entry.

Dispatch hint

  • Workflow: .github/workflows/nightly-e2e.yaml
  • jobs input: onboard-resume-e2e,onboard-repair-e2e,cloud-onboard-e2e,openclaw-inference-switch-e2e,openclaw-anthropic-inference-switch-e2e,hermes-inference-switch-e2e,hermes-anthropic-inference-switch-e2e,inference-routing-e2e,rebuild-openclaw-e2e,rebuild-hermes-e2e,double-onboard-e2e,messaging-compatible-endpoint-e2e

@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Recommendation

Required Vitest E2E scenarios: double-onboard-vitest, openclaw-inference-switch-vitest, rebuild-hermes-stale-base-vitest, rebuild-hermes-vitest, onboard-resume-vitest, onboard-repair-vitest
Optional Vitest E2E scenarios: gpu-double-onboard-vitest

Dispatch required Vitest E2E scenarios:

  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=double-onboard-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=openclaw-inference-switch-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=rebuild-hermes-stale-base-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=rebuild-hermes-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=onboard-resume-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=onboard-repair-vitest

Workflow run

Full Vitest E2E advisor summary

Vitest E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required Vitest E2E scenarios

  • double-onboard-vitest: Focused free-standing Vitest job wired for changed live test test/e2e-scenario/live/double-onboard.test.ts.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=double-onboard-vitest
  • openclaw-inference-switch-vitest: Focused free-standing Vitest job wired for changed live test test/e2e-scenario/live/openclaw-inference-switch.test.ts.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=openclaw-inference-switch-vitest
  • rebuild-hermes-stale-base-vitest: Focused free-standing Vitest job wired for changed live test test/e2e-scenario/live/rebuild-hermes.test.ts.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=rebuild-hermes-stale-base-vitest
  • rebuild-hermes-vitest: Focused free-standing Vitest job wired for changed live test test/e2e-scenario/live/rebuild-hermes.test.ts.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=rebuild-hermes-vitest
  • onboard-resume-vitest: Required by the onboarding resume compatibility rule: the PR changes src/lib/onboard/machine/handlers/sandbox.ts, src/lib/onboard.ts, session bootstrap/registry inference metadata, and rebuild resume state rewriting, all of which can affect persisted-session resume compatibility.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=onboard-resume-vitest
  • onboard-repair-vitest: Required alongside onboard-resume for these state-machine/session paths because the changes can affect repair/backstop execution from persisted sessions and registry-derived recreate metadata.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=onboard-repair-vitest

Optional Vitest E2E scenarios

  • gpu-double-onboard-vitest: Optional adjacent special-runner coverage for double-onboard behavior with GPU/local-provider onboarding. Useful if the registry inference metadata changes need GPU-path confirmation, but not the primary path for this PR.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=gpu-double-onboard-vitest

Relevant changed files

  • src/lib/actions/inference-set.ts
  • src/lib/actions/sandbox/rebuild-resume-config.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/inference/selection.ts
  • src/lib/onboard.ts
  • src/lib/onboard/machine/handlers/sandbox.ts
  • src/lib/onboard/sandbox-registration.ts
  • src/lib/state/registry.ts
  • test/e2e-scenario/live/double-onboard.test.ts
  • test/e2e-scenario/live/openclaw-inference-switch.test.ts
  • test/e2e-scenario/live/rebuild-hermes.test.ts

Comment thread src/lib/actions/inference-set.test.ts Fixed
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 28249175430
Target ref: fix/rebuild-inference-selection-metadata
Workflow ref: main
Requested jobs: double-onboard-e2e,rebuild-openclaw-e2e,upgrade-stale-sandbox-e2e
Summary: 0 passed, 2 failed, 1 cancelled, 0 skipped

Job Result
double-onboard-e2e ⚠️ cancelled
rebuild-openclaw-e2e ❌ failure
upgrade-stale-sandbox-e2e ❌ failure

Failed jobs: rebuild-openclaw-e2e, upgrade-stale-sandbox-e2e. Check run artifacts for logs.

@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Changes requested

Merge posture: Do not merge yet
Primary next action: Resolve or justify PRA-1: Source-of-truth review needed: Inference-set expanded registry metadata.
Open items: 0 required · 6 warnings · 0 suggestions · 8 test follow-ups
Since last review: 2 prior items resolved · 0 still apply · 2 new items found

Action checklist

  • PRA-1 Resolve or justify: Source-of-truth review needed: Inference-set expanded registry metadata
  • PRA-2 Resolve or justify: Source-of-truth review needed: Rebuild custom endpoint recovery
  • PRA-3 Resolve or justify: Source-of-truth review needed: Durable custom endpoint URL validation
  • PRA-4 Resolve or justify: Matching custom-compatible sessions can be overwritten with inference.local and later beat the durable registry endpoint in src/lib/actions/inference-set.ts:318
  • PRA-5 Resolve or justify: Same-provider custom-compatible switches can still keep null durable endpoint metadata in src/lib/actions/inference-set.ts:398
  • PRA-6 Resolve or justify: Durable custom endpoint metadata lacks an explicit SSRF-sensitive host policy in src/lib/actions/sandbox/rebuild-resume-config.ts:114
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: Acceptance clause
  • PRA-T6 Add or justify test follow-up: Inference-set expanded registry metadata
  • PRA-T7 Add or justify test follow-up: Rebuild custom endpoint recovery
  • PRA-T8 Add or justify test follow-up: Durable custom endpoint URL validation

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-3 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-4 Resolve/justify correctness src/lib/actions/inference-set.ts:318 For custom-compatible providers, keep the trusted custom endpoint metadata in the matching session instead of replacing it with `getProviderSelectionConfig()`'s managed route. During rebuild, prefer the validated durable registry endpoint when the matching session endpoint is missing or differs from the registry's custom endpoint metadata, or explicitly reconcile the session from the registry before `pinEndpoint` is computed.
PRA-5 Resolve/justify correctness src/lib/actions/inference-set.ts:398 For custom-compatible providers, require a durable endpoint source regardless of whether the provider name changed: use a matching sandbox/provider/model session if it supplies the endpoint, keep existing non-empty registry metadata, or reject before the route mutation when neither source is available.
PRA-6 Resolve/justify security src/lib/actions/sandbox/rebuild-resume-config.ts:114 Either enforce the same endpoint host policy used during onboarding at `canonicalCustomEndpointUrl()`, or explicitly document that durable custom-compatible endpoints may target local/private hosts and add focused tests for the accepted and rejected host classes. Keep the existing scheme/userinfo/query/hash defenses.
Review findings by urgency: 0 required fixes, 6 items to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: Inference-set expanded registry metadata

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Missing tests for `runInferenceSet` preserving compatible endpoint session metadata and rejecting/hydrating same-provider legacy custom-compatible switches.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `updateMatchingOnboardSession()` writes `getProviderSelectionConfig(...).endpointUrl`; `registryMetadataForProviderSwitch()` returns same-provider registry fields before checking matching sessions or rejecting custom providers.

PRA-2 Resolve/justify — Source-of-truth review needed: Rebuild custom endpoint recovery

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Missing `prepareRebuildResumeConfig uses durable registry endpoint when matching session endpoint is stale or missing`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `prepareRebuildResumeConfig()` computes a valid `rebuildEndpoint` but returns `pinEndpoint: !sessionMatchesSandbox && rebuildEndpoint.known`, leaving matching stale sessions unpinned.

PRA-3 Resolve/justify — Source-of-truth review needed: Durable custom endpoint URL validation

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Missing tests for metadata-service/link-local/private/loopback host behavior, either rejected or documented as allowed.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `canonicalCustomEndpointUrl()` checks scheme/userinfo but not host classes; tests accept `http://127.0.0.1:19999/v1\`.

PRA-4 Resolve/justify — Matching custom-compatible sessions can be overwritten with inference.local and later beat the durable registry endpoint

  • Location: src/lib/actions/inference-set.ts:318
  • Category: correctness
  • Problem: `runInferenceSet()` now correctly derives registry metadata before switching, but `updateMatchingOnboardSession()` still rewrites `current.endpointUrl` from `getProviderSelectionConfig(provider, model)`. For `compatible-endpoint` and `compatible-anthropic-endpoint`, that helper returns NemoClaw's sandbox-facing route (`https://inference.local/v1\`\) rather than the operator's real custom base URL. Then `prepareRebuildResumeConfig()` only pins the registry endpoint when the loaded session does not match the sandbox, so a matching session with this stale value can be kept during rebuild even though the registry has the correct durable endpoint.
  • Impact: A custom-compatible sandbox can have correct registry metadata but a matching onboard session that points at `inference.local`; a normal rebuild from that matching session can recreate against the wrong endpoint or fail, undermining the durable-registry recovery this PR is adding.
  • Recommended action: For custom-compatible providers, keep the trusted custom endpoint metadata in the matching session instead of replacing it with `getProviderSelectionConfig()`'s managed route. During rebuild, prefer the validated durable registry endpoint when the matching session endpoint is missing or differs from the registry's custom endpoint metadata, or explicitly reconcile the session from the registry before `pinEndpoint` is computed.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `src/lib/actions/inference-set.ts` around `updateMatchingOnboardSession()` and compare it with `getProviderSelectionConfig()` in `src/lib/inference/config.ts`; then read `prepareRebuildResumeConfig()` where `pinEndpoint` is `!sessionMatchesSandbox && rebuildEndpoint.known`.
  • Missing regression test: Add `runInferenceSet preserves the matching compatible-endpoint session endpoint instead of writing inference.local`, and add `prepareRebuildResumeConfig uses durable registry endpoint when matching session endpoint is stale or missing`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `src/lib/actions/inference-set.ts` around `updateMatchingOnboardSession()` and compare it with `getProviderSelectionConfig()` in `src/lib/inference/config.ts`; then read `prepareRebuildResumeConfig()` where `pinEndpoint` is `!sessionMatchesSandbox && rebuildEndpoint.known`.
  • Evidence: `updateMatchingOnboardSession()` assigns `current.endpointUrl = getProviderSelectionConfig(provider, model)?.endpointUrl ?? current.endpointUrl`; `getProviderSelectionConfig()` uses `INFERENCE_ROUTE_URL` for compatible providers; `prepareRebuildResumeConfig()` returns `pinEndpoint: !sessionMatchesSandbox && rebuildEndpoint.known`.

PRA-5 Resolve/justify — Same-provider custom-compatible switches can still keep null durable endpoint metadata

  • Location: src/lib/actions/inference-set.ts:398
  • Category: correctness
  • Problem: `registryMetadataForProviderSwitch()` returns the registry metadata immediately when `entry.provider === provider`, even if that provider is custom-compatible and the legacy entry has no `endpointUrl`. In that path it does not fall back to a matching session that may contain the endpoint, and it does not reject before calling OpenShell. The new rejection only applies when switching provider families.
  • Impact: A legacy `compatible-endpoint` or `compatible-anthropic-endpoint` sandbox can switch models and leave the registry with the new model but no durable endpoint metadata, so unrelated-session rebuild recovery remains unavailable for that sandbox despite this PR's expanded metadata contract.
  • Recommended action: For custom-compatible providers, require a durable endpoint source regardless of whether the provider name changed: use a matching sandbox/provider/model session if it supplies the endpoint, keep existing non-empty registry metadata, or reject before the route mutation when neither source is available.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect `registryMetadataForProviderSwitch()` in `src/lib/actions/inference-set.ts`: the `entry.provider === provider` branch returns before `matchingSessionMetadata()` and before the custom-provider rejection.
  • Missing regression test: Add `runInferenceSet rejects same-provider compatible-endpoint switches when neither registry nor matching session has durable endpoint metadata`, plus a positive case if matching-session metadata should hydrate a legacy same-provider entry.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect `registryMetadataForProviderSwitch()` in `src/lib/actions/inference-set.ts`: the `entry.provider === provider` branch returns before `matchingSessionMetadata()` and before the custom-provider rejection.
  • Evidence: The early `if (entry.provider === provider) return { endpointUrl: entry.endpointUrl ?? null, ... }` branch can produce null endpoint metadata for `compatible-endpoint`; the existing new negative test covers only `nvidia-prod` to `compatible-endpoint`.

PRA-6 Resolve/justify — Durable custom endpoint metadata lacks an explicit SSRF-sensitive host policy

  • Location: src/lib/actions/sandbox/rebuild-resume-config.ts:114
  • Category: security
  • Problem: The rebuild trust boundary now accepts durable custom endpoint metadata from the registry after URL parsing, scheme checking, userinfo rejection, and query/hash stripping. It does not document or enforce a host policy for loopback, link-local, metadata-service, private-network, or DNS-rebinding-sensitive hosts; the changed tests explicitly accept `http://127.0.0.1:19999/v1\`. Arbitrary custom endpoints may be intended, but this should be explicit at the durable rebuild boundary because registry metadata can outlive the original interactive validation context.
  • Impact: If a registry entry is stale or tampered, rebuild can pin an arbitrary HTTP(S) target for recreated inference traffic, including internal or loopback services, expanding the blast radius of registry tampering and weakening SSRF/network-policy expectations.
  • Recommended action: Either enforce the same endpoint host policy used during onboarding at `canonicalCustomEndpointUrl()`, or explicitly document that durable custom-compatible endpoints may target local/private hosts and add focused tests for the accepted and rejected host classes. Keep the existing scheme/userinfo/query/hash defenses.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `canonicalCustomEndpointUrl()` and `getRebuildEndpointFromRegistry()` in `src/lib/actions/sandbox/rebuild-resume-config.ts`, then compare the tests that accept `http://127.0.0.1:19999/v1\` and reject only malformed, `file:`, and userinfo URLs.
  • Missing regression test: Add `getRebuildEndpointFromRegistry rejects metadata-service and link-local custom endpoint URLs` if those are disallowed, or `getRebuildEndpointFromRegistry documents allowed loopback/private custom endpoints and rejects only unsupported schemes/userinfo` if arbitrary custom hosts are intentional.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `canonicalCustomEndpointUrl()` and `getRebuildEndpointFromRegistry()` in `src/lib/actions/sandbox/rebuild-resume-config.ts`, then compare the tests that accept `http://127.0.0.1:19999/v1\` and reject only malformed, `file:`, and userinfo URLs.
  • Evidence: `canonicalCustomEndpointUrl()` only checks `http:`/`https:` and userinfo before returning `${url.origin}${url.pathname}`; the changed unit test expects `http://127.0.0.1:19999/v1\` to be accepted.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — runInferenceSet preserves the matching compatible-endpoint session endpoint instead of writing inference.local. The PR changes sandbox lifecycle, OpenShell inference routing, registry/session persistence, and rebuild recovery. It adds meaningful unit and live E2E coverage, but the remaining risks are behavioral cross-boundary cases that mocks alone can miss.
  • PRA-T2 Runtime validation — prepareRebuildResumeConfig uses durable registry endpoint when matching session endpoint is stale or missing. The PR changes sandbox lifecycle, OpenShell inference routing, registry/session persistence, and rebuild recovery. It adds meaningful unit and live E2E coverage, but the remaining risks are behavioral cross-boundary cases that mocks alone can miss.
  • PRA-T3 Runtime validation — runInferenceSet rejects same-provider compatible-endpoint switches when neither registry nor matching session has durable endpoint metadata. The PR changes sandbox lifecycle, OpenShell inference routing, registry/session persistence, and rebuild recovery. It adds meaningful unit and live E2E coverage, but the remaining risks are behavioral cross-boundary cases that mocks alone can miss.
  • PRA-T4 Runtime validation — getRebuildEndpointFromRegistry rejects metadata-service and link-local custom endpoint URLs, or documents allowed loopback/private custom endpoints with explicit tests. The PR changes sandbox lifecycle, OpenShell inference routing, registry/session persistence, and rebuild recovery. It adds meaningful unit and live E2E coverage, but the remaining risks are behavioral cross-boundary cases that mocks alone can miss.
  • PRA-T5 Acceptance clause — Keep inference-set registry updates in sync with the expanded metadata. — add test evidence or identify existing coverage. `runInferenceSet()` prewrites and refreshes expanded registry fields, and tests cover cross-provider compatible Anthropic metadata and rejection without trusted metadata. Remaining gaps: matching custom-compatible sessions can be overwritten with `inference.local`, and same-provider legacy custom-compatible entries can keep null durable endpoint metadata.
  • PRA-T6 Inference-set expanded registry metadata — Missing tests for `runInferenceSet` preserving compatible endpoint session metadata and rejecting/hydrating same-provider legacy custom-compatible switches.. `updateMatchingOnboardSession()` writes `getProviderSelectionConfig(...).endpointUrl`; `registryMetadataForProviderSwitch()` returns same-provider registry fields before checking matching sessions or rejecting custom providers.
  • PRA-T7 Rebuild custom endpoint recovery — Missing `prepareRebuildResumeConfig uses durable registry endpoint when matching session endpoint is stale or missing`.. `prepareRebuildResumeConfig()` computes a valid `rebuildEndpoint` but returns `pinEndpoint: !sessionMatchesSandbox && rebuildEndpoint.known`, leaving matching stale sessions unpinned.
  • PRA-T8 Durable custom endpoint URL validation — Missing tests for metadata-service/link-local/private/loopback host behavior, either rejected or documented as allowed.. `canonicalCustomEndpointUrl()` checks scheme/userinfo but not host classes; tests accept `http://127.0.0.1:19999/v1\`.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: Inference-set expanded registry metadata

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Missing tests for `runInferenceSet` preserving compatible endpoint session metadata and rejecting/hydrating same-provider legacy custom-compatible switches.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `updateMatchingOnboardSession()` writes `getProviderSelectionConfig(...).endpointUrl`; `registryMetadataForProviderSwitch()` returns same-provider registry fields before checking matching sessions or rejecting custom providers.

PRA-2 Resolve/justify — Source-of-truth review needed: Rebuild custom endpoint recovery

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Missing `prepareRebuildResumeConfig uses durable registry endpoint when matching session endpoint is stale or missing`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `prepareRebuildResumeConfig()` computes a valid `rebuildEndpoint` but returns `pinEndpoint: !sessionMatchesSandbox && rebuildEndpoint.known`, leaving matching stale sessions unpinned.

PRA-3 Resolve/justify — Source-of-truth review needed: Durable custom endpoint URL validation

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Missing tests for metadata-service/link-local/private/loopback host behavior, either rejected or documented as allowed.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `canonicalCustomEndpointUrl()` checks scheme/userinfo but not host classes; tests accept `http://127.0.0.1:19999/v1\`.

PRA-4 Resolve/justify — Matching custom-compatible sessions can be overwritten with inference.local and later beat the durable registry endpoint

  • Location: src/lib/actions/inference-set.ts:318
  • Category: correctness
  • Problem: `runInferenceSet()` now correctly derives registry metadata before switching, but `updateMatchingOnboardSession()` still rewrites `current.endpointUrl` from `getProviderSelectionConfig(provider, model)`. For `compatible-endpoint` and `compatible-anthropic-endpoint`, that helper returns NemoClaw's sandbox-facing route (`https://inference.local/v1\`\) rather than the operator's real custom base URL. Then `prepareRebuildResumeConfig()` only pins the registry endpoint when the loaded session does not match the sandbox, so a matching session with this stale value can be kept during rebuild even though the registry has the correct durable endpoint.
  • Impact: A custom-compatible sandbox can have correct registry metadata but a matching onboard session that points at `inference.local`; a normal rebuild from that matching session can recreate against the wrong endpoint or fail, undermining the durable-registry recovery this PR is adding.
  • Recommended action: For custom-compatible providers, keep the trusted custom endpoint metadata in the matching session instead of replacing it with `getProviderSelectionConfig()`'s managed route. During rebuild, prefer the validated durable registry endpoint when the matching session endpoint is missing or differs from the registry's custom endpoint metadata, or explicitly reconcile the session from the registry before `pinEndpoint` is computed.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `src/lib/actions/inference-set.ts` around `updateMatchingOnboardSession()` and compare it with `getProviderSelectionConfig()` in `src/lib/inference/config.ts`; then read `prepareRebuildResumeConfig()` where `pinEndpoint` is `!sessionMatchesSandbox && rebuildEndpoint.known`.
  • Missing regression test: Add `runInferenceSet preserves the matching compatible-endpoint session endpoint instead of writing inference.local`, and add `prepareRebuildResumeConfig uses durable registry endpoint when matching session endpoint is stale or missing`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `src/lib/actions/inference-set.ts` around `updateMatchingOnboardSession()` and compare it with `getProviderSelectionConfig()` in `src/lib/inference/config.ts`; then read `prepareRebuildResumeConfig()` where `pinEndpoint` is `!sessionMatchesSandbox && rebuildEndpoint.known`.
  • Evidence: `updateMatchingOnboardSession()` assigns `current.endpointUrl = getProviderSelectionConfig(provider, model)?.endpointUrl ?? current.endpointUrl`; `getProviderSelectionConfig()` uses `INFERENCE_ROUTE_URL` for compatible providers; `prepareRebuildResumeConfig()` returns `pinEndpoint: !sessionMatchesSandbox && rebuildEndpoint.known`.

PRA-5 Resolve/justify — Same-provider custom-compatible switches can still keep null durable endpoint metadata

  • Location: src/lib/actions/inference-set.ts:398
  • Category: correctness
  • Problem: `registryMetadataForProviderSwitch()` returns the registry metadata immediately when `entry.provider === provider`, even if that provider is custom-compatible and the legacy entry has no `endpointUrl`. In that path it does not fall back to a matching session that may contain the endpoint, and it does not reject before calling OpenShell. The new rejection only applies when switching provider families.
  • Impact: A legacy `compatible-endpoint` or `compatible-anthropic-endpoint` sandbox can switch models and leave the registry with the new model but no durable endpoint metadata, so unrelated-session rebuild recovery remains unavailable for that sandbox despite this PR's expanded metadata contract.
  • Recommended action: For custom-compatible providers, require a durable endpoint source regardless of whether the provider name changed: use a matching sandbox/provider/model session if it supplies the endpoint, keep existing non-empty registry metadata, or reject before the route mutation when neither source is available.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect `registryMetadataForProviderSwitch()` in `src/lib/actions/inference-set.ts`: the `entry.provider === provider` branch returns before `matchingSessionMetadata()` and before the custom-provider rejection.
  • Missing regression test: Add `runInferenceSet rejects same-provider compatible-endpoint switches when neither registry nor matching session has durable endpoint metadata`, plus a positive case if matching-session metadata should hydrate a legacy same-provider entry.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect `registryMetadataForProviderSwitch()` in `src/lib/actions/inference-set.ts`: the `entry.provider === provider` branch returns before `matchingSessionMetadata()` and before the custom-provider rejection.
  • Evidence: The early `if (entry.provider === provider) return { endpointUrl: entry.endpointUrl ?? null, ... }` branch can produce null endpoint metadata for `compatible-endpoint`; the existing new negative test covers only `nvidia-prod` to `compatible-endpoint`.

PRA-6 Resolve/justify — Durable custom endpoint metadata lacks an explicit SSRF-sensitive host policy

  • Location: src/lib/actions/sandbox/rebuild-resume-config.ts:114
  • Category: security
  • Problem: The rebuild trust boundary now accepts durable custom endpoint metadata from the registry after URL parsing, scheme checking, userinfo rejection, and query/hash stripping. It does not document or enforce a host policy for loopback, link-local, metadata-service, private-network, or DNS-rebinding-sensitive hosts; the changed tests explicitly accept `http://127.0.0.1:19999/v1\`. Arbitrary custom endpoints may be intended, but this should be explicit at the durable rebuild boundary because registry metadata can outlive the original interactive validation context.
  • Impact: If a registry entry is stale or tampered, rebuild can pin an arbitrary HTTP(S) target for recreated inference traffic, including internal or loopback services, expanding the blast radius of registry tampering and weakening SSRF/network-policy expectations.
  • Recommended action: Either enforce the same endpoint host policy used during onboarding at `canonicalCustomEndpointUrl()`, or explicitly document that durable custom-compatible endpoints may target local/private hosts and add focused tests for the accepted and rejected host classes. Keep the existing scheme/userinfo/query/hash defenses.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `canonicalCustomEndpointUrl()` and `getRebuildEndpointFromRegistry()` in `src/lib/actions/sandbox/rebuild-resume-config.ts`, then compare the tests that accept `http://127.0.0.1:19999/v1\` and reject only malformed, `file:`, and userinfo URLs.
  • Missing regression test: Add `getRebuildEndpointFromRegistry rejects metadata-service and link-local custom endpoint URLs` if those are disallowed, or `getRebuildEndpointFromRegistry documents allowed loopback/private custom endpoints and rejects only unsupported schemes/userinfo` if arbitrary custom hosts are intentional.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `canonicalCustomEndpointUrl()` and `getRebuildEndpointFromRegistry()` in `src/lib/actions/sandbox/rebuild-resume-config.ts`, then compare the tests that accept `http://127.0.0.1:19999/v1\` and reject only malformed, `file:`, and userinfo URLs.
  • Evidence: `canonicalCustomEndpointUrl()` only checks `http:`/`https:` and userinfo before returning `${url.origin}${url.pathname}`; the changed unit test expects `http://127.0.0.1:19999/v1\` to be accepted.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 28249336378
Target ref: d556f84ac38b8681e0836489bc40ea083b3defef
Workflow ref: main
Requested jobs: onboard-resume-e2e
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
onboard-resume-e2e ✅ success

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

🧹 Nitpick comments (1)
src/lib/actions/inference-set.test.ts (1)

108-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Let the helper assert preserved metadata too.

Hard-coding endpointUrl, credentialEnv, and nimContainer to null means this helper only covers provider-switch cases. That forces the later tests to fall back to expect.objectContaining({ provider, model }), which no longer exercises the expanded registry payload this PR adds. Make those fields configurable so the suite can verify both “preserved” and “cleared” cases.

Suggested helper shape
 function expectInferenceRegistryUpdate(
   updateSandbox: ReturnType<typeof vi.fn>,
   sandboxName: string,
-  expected: { provider: string; model: string; preferredInferenceApi?: string | null },
+  expected: {
+    provider: string;
+    model: string;
+    endpointUrl?: string | null;
+    credentialEnv?: string | null;
+    preferredInferenceApi?: string | null;
+    nimContainer?: string | null;
+  },
 ): void {
   expect(updateSandbox).toHaveBeenCalledWith(
     sandboxName,
     expect.objectContaining({
       provider: expected.provider,
       model: expected.model,
-      endpointUrl: null,
-      credentialEnv: null,
+      endpointUrl: expected.endpointUrl ?? null,
+      credentialEnv: expected.credentialEnv ?? null,
       preferredInferenceApi: expected.preferredInferenceApi ?? null,
-      nimContainer: null,
+      nimContainer: expected.nimContainer ?? null,
     }),
   );
 }
🤖 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 `@src/lib/actions/inference-set.test.ts` around lines 108 - 124, The helper in
expectInferenceRegistryUpdate is too restrictive because it hard-codes
endpointUrl, credentialEnv, and nimContainer to null, so it cannot verify
preserved metadata in the registry payload. Update this helper to accept
optional expected values for those fields (alongside provider, model, and
preferredInferenceApi) and assert against them in the toHaveBeenCalledWith
expectation, so tests can cover both cleared and preserved cases without falling
back to loose objectContaining checks.
🤖 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 `@src/lib/actions/inference-set.ts`:
- Around line 442-459: Clear all provider-specific metadata when the provider
changes in inference-set update logic. In the registry write path inside the
sandbox update call, the current switch handling only nulls endpointUrl, which
leaves credentialEnv and nimContainer from the previous provider behind. Update
the selection fields construction so provider switches reset all provider-scoped
fields together, using the existing inferenceSelectionRegistryFields path and
the provider comparison around entry.provider.

In `@src/lib/actions/sandbox/rebuild.ts`:
- Around line 428-430: The preflight credential selection in
prepareRebuildResumeConfig is inconsistent with recreate because it prefers
session?.credentialEnv when sessionMatchesTarget is true, even though the
sandbox credential is later rewritten from the registry. Update the
rebuildCredentialEnv branch to source credentials the same way recreate does by
using getRebuildCredentialEnvFromRegistry for the matching-session case as well,
and keep the logic aligned with sb.provider and sb.credentialEnv so preflight
validates the same env that recreate will use.

In `@src/lib/inference/selection.ts`:
- Around line 15-16: The nullableString helper in selection.ts is returning the
original string instead of the normalized value, so whitespace survives even
after validation. Update nullableString() to trim the accepted string before
returning it, while keeping the existing empty-string guard, so registry
metadata and later comparisons use the canonical value.

In `@src/lib/onboard.ts`:
- Around line 3194-3205: The sandbox registry write in createSandbox is reading
onboardSession.loadSession() too late, so it can persist inference metadata from
a different in-progress onboard. Capture the session selection once near the
start of createSandbox and reuse that snapshot when calling
sandboxRegistration.registerCreatedSandbox, or at minimum gate the late-loaded
session on session.sandboxName matching sandboxName before using endpointUrl,
credentialEnv, and nimContainer.

---

Nitpick comments:
In `@src/lib/actions/inference-set.test.ts`:
- Around line 108-124: The helper in expectInferenceRegistryUpdate is too
restrictive because it hard-codes endpointUrl, credentialEnv, and nimContainer
to null, so it cannot verify preserved metadata in the registry payload. Update
this helper to accept optional expected values for those fields (alongside
provider, model, and preferredInferenceApi) and assert against them in the
toHaveBeenCalledWith expectation, so tests can cover both cleared and preserved
cases without falling back to loose objectContaining checks.
🪄 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: 607e5600-7f47-462d-b2de-df6bde917f36

📥 Commits

Reviewing files that changed from the base of the PR and between c1c7c1d and d556f84.

📒 Files selected for processing (12)
  • src/lib/actions/inference-set.test.ts
  • src/lib/actions/inference-set.ts
  • src/lib/actions/sandbox/rebuild-resume-config.test.ts
  • src/lib/actions/sandbox/rebuild-resume-config.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/inference/selection.ts
  • src/lib/onboard.ts
  • src/lib/onboard/machine/handlers/sandbox.ts
  • src/lib/onboard/sandbox-registration.test.ts
  • src/lib/onboard/sandbox-registration.ts
  • src/lib/state/registry.ts
  • test/registry.test.ts

Comment thread src/lib/actions/inference-set.ts Outdated
Comment thread src/lib/actions/sandbox/rebuild.ts Outdated
Comment thread src/lib/inference/selection.ts Outdated
Comment thread src/lib/onboard.ts Outdated

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

LGTM once feedback is addressed

@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

🧹 Nitpick comments (1)
test/e2e-scenario/live/openclaw-inference-switch.test.ts (1)

479-489: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the session-side inference metadata as well.

This helper now verifies endpointUrl/credentialEnv on the registry entry, but the session branch only checks preferredInferenceApi. If onboard-session.json stops persisting endpointUrl or credentialEnv, this scenario still passes even though those fields are part of the persisted session contract for rebuild recovery.

Suggested test tightening
   expect(session.sandboxName).toBe(SANDBOX_NAME);
   expect(session.provider).toBe(SWITCH_PROVIDER);
   expect(session.model).toBe(SWITCH_MODEL);
   if (SWITCH_PROVIDER === "compatible-endpoint") {
+    expect(session.endpointUrl).toBe(options.hostedEndpointUrl);
+    expect(session.credentialEnv).toBe("COMPATIBLE_API_KEY");
     expect(session.preferredInferenceApi).toBe("openai-completions");
   } else if (SWITCH_PROVIDER === "compatible-anthropic-endpoint") {
+    expect(session.endpointUrl).toBe(
+      process.env.NEMOCLAW_SWITCH_ENDPOINT_URL ?? options.mockProvider?.endpointUrl,
+    );
+    expect(session.credentialEnv).toBe("COMPATIBLE_ANTHROPIC_API_KEY");
     expect(session.preferredInferenceApi).toBe("anthropic-messages");
+  } else {
+    expect(session.endpointUrl).toBeNull();
+    expect(session.credentialEnv).toBeNull();
+    expect(session.preferredInferenceApi).toBeNull();
   }
🤖 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-scenario/live/openclaw-inference-switch.test.ts` around lines 479 -
489, The session assertions in the onboard-session check only verify
preferredInferenceApi, so the persisted rebuild-recovery contract for
endpointUrl and credentialEnv is not covered. Tighten the test in
openclaw-inference-switch by extending the existing session branch that reads
onboard-session.json and asserts OnboardSession fields to also check endpointUrl
and credentialEnv for the compatible-endpoint and compatible-anthropic-endpoint
cases, matching the registry entry expectations.
🤖 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-scenario/live/double-onboard.test.ts`:
- Around line 333-339: The registryHas() helper in double-onboard.test.ts is
dropping legacy string-array matches because the Array.isArray(registry) branch
only returns object values and turns matching strings into null. Update the
matching logic so registryHas() correctly treats both string entries and object
entries with a name field as valid hits, and return a truthy result for the
string-array legacy format without narrowing everything to Record<string,
unknown>.

---

Nitpick comments:
In `@test/e2e-scenario/live/openclaw-inference-switch.test.ts`:
- Around line 479-489: The session assertions in the onboard-session check only
verify preferredInferenceApi, so the persisted rebuild-recovery contract for
endpointUrl and credentialEnv is not covered. Tighten the test in
openclaw-inference-switch by extending the existing session branch that reads
onboard-session.json and asserts OnboardSession fields to also check endpointUrl
and credentialEnv for the compatible-endpoint and compatible-anthropic-endpoint
cases, matching the registry entry expectations.
🪄 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: 8804d035-afcb-4ba5-9db5-293cdbd4cbb5

📥 Commits

Reviewing files that changed from the base of the PR and between d556f84 and 2ae9212.

📒 Files selected for processing (3)
  • test/e2e-scenario/live/double-onboard.test.ts
  • test/e2e-scenario/live/openclaw-inference-switch.test.ts
  • test/e2e-scenario/live/rebuild-hermes.test.ts

Comment thread test/e2e-scenario/live/double-onboard.test.ts Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ⚠️ Run cancelled — no signal

Run: 28250695850
Target ref: 255081d867351086518b6489d0b4453b5cebb3b4
Workflow ref: main
Requested jobs: onboard-resume-e2e,double-onboard-e2e
Summary: 0 passed, 0 failed, 2 cancelled, 0 skipped

Job Result
double-onboard-e2e ⚠️ cancelled
onboard-resume-e2e ⚠️ cancelled

@wscurran wscurran added area: inference Inference routing, serving, model selection, or outputs area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery bug-fix PR fixes a bug or regression labels Jun 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All selected jobs passed

Run: 28250183708
Workflow ref: fix/rebuild-inference-selection-metadata
Requested scenarios: double-onboard,rebuild-hermes,openclaw-inference-switch
Requested jobs: (default — all default-enabled free-standing jobs; explicit-only jobs such as jetson-nvmap-gpu-vitest are skipped unless selected)
Summary: 3 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
double-onboard-vitest ✅ success
openclaw-inference-switch-vitest ✅ success
rebuild-hermes-vitest ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ⚠️ Some jobs cancelled — partial pass

Run: 28250839540
Target ref: 51e02f0d03f5ed16c4774467b600b6be95da245c
Workflow ref: main
Requested jobs: onboard-resume-e2e,double-onboard-e2e
Summary: 1 passed, 0 failed, 1 cancelled, 0 skipped

Job Result
double-onboard-e2e ⚠️ cancelled
onboard-resume-e2e ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ⚠️ Run cancelled — no signal

Run: 28251429602
Target ref: cee56d2e0ad1e16cda34503158de7e0dc8a21092
Workflow ref: main
Requested jobs: onboard-resume-e2e,double-onboard-e2e
Summary: 0 passed, 0 failed, 2 cancelled, 0 skipped

Job Result
double-onboard-e2e ⚠️ cancelled
onboard-resume-e2e ⚠️ cancelled

@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 28251617517
Target ref: 1bcba69224665efc034b167425a4d8344167e189
Workflow ref: main
Requested jobs: onboard-resume-e2e,double-onboard-e2e
Summary: 2 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
double-onboard-e2e ✅ success
onboard-resume-e2e ✅ success

@jyaunches
jyaunches merged commit 5b001aa into main Jun 26, 2026
41 checks passed
@jyaunches
jyaunches deleted the fix/rebuild-inference-selection-metadata branch June 26, 2026 17:29
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 28254108306
Target ref: 07b38f350fb14c657b02d5ae23c2afda41e276ff
Workflow ref: main
Requested jobs: onboard-resume-e2e,double-onboard-e2e,messaging-compatible-endpoint-e2e
Summary: 2 passed, 1 failed, 0 cancelled, 0 skipped

Job Result
double-onboard-e2e ❌ failure
messaging-compatible-endpoint-e2e ✅ success
onboard-resume-e2e ✅ success

Failed jobs: double-onboard-e2e. Check run artifacts for logs.

jyaunches added a commit that referenced this pull request Jun 26, 2026
## Summary
- Add explicit trusted metadata flags for compatible custom provider
switches: endpoint URL, credential env, and inference API.
- Persist explicit metadata into sandbox registry and matching onboard
session during inference set.
- Update OpenClaw/Hermes Anthropic inference-switch E2Es to pass mock
endpoint metadata instead of relying on unrelated session state.

## Why
Nightly openclaw-anthropic-inference-switch-e2e and
hermes-anthropic-inference-switch-e2e fail after PR #5869 because the
new source-boundary guard correctly refuses cross-provider
compatible-Anthropic switches without durable endpoint metadata. This PR
keeps that guard intact while giving the switch command a first-class
trusted metadata path.

## Validation
- npm run build:cli
- npm test -- src/lib/actions/inference-set.test.ts
src/commands/global-oclif-command-adapters.test.ts

## Related
- Regression from PR #5869


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added optional `--endpoint-url`, `--credential-env`, and
`--inference-api` flags to the Hermes/NemoClaw “inference set” commands.
* **Bug Fixes**
* Enhanced compatible-provider switching by validating allowed
`--inference-api` values, persisting durable rebuild metadata, and
synchronizing onboarding settings (including `endpoint-url`
normalization).
* **Documentation**
* Updated command references and compatibility guidance, including
trusted `--endpoint-url` requirements and allowed `--inference-api`
values.
* **Tests**
* Expanded unit and end-to-end scenarios to cover the new flags and
compatible switch behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
cv added a commit that referenced this pull request Jun 26, 2026
## Summary
- preserve the validated recreate endpoint in rebuild resume config even
when the existing session matches the sandbox name
- overwrite the resume session endpoint before `onboard --resume` so
stale-recovery retries cannot reuse an old/partial session endpoint
- point `double-onboard-e2e` stale rebuild diagnostics at the actual
rebuild output

## Context
Follow-up to PR #5869 and issue #4497 after `double-onboard-e2e` showed
stale rebuild recovery still recreating the wrong sandbox path / hiding
the actual rebuild output.

## Validation
- `npm run build:cli`
- `npm test -- src/lib/actions/sandbox/rebuild-resume-config.test.ts
src/lib/onboard/sandbox-registration.test.ts test/registry.test.ts
src/lib/actions/inference-set.test.ts
src/lib/actions/sandbox/rebuild-gateway-drift.test.ts`
- `bash -n test/e2e/test-double-onboard.sh`

Note: local commit/push hooks were attempted; the long-running hook
process was killed by the harness (signal 9), so commit/push used
`--no-verify` after the focused validation above passed.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Strengthened sandbox rebuild/resume so `onboard --resume` consistently
uses the validated recreate endpoint, avoiding stale
session/provider/model data from steering recovery.
* Added stricter, fail-closed custom-endpoint handling with URL
canonicalization and correct precedence when durable registry metadata
is available.
* Enforced env-driven, target-scoped endpoint selection/validation
(rejecting invalid, mismatched, or unsupported URLs).
* **Tests**
* Expanded rebuild/resume coverage across matching, stale, non-matching,
missing, and invalid custom-endpoint scenarios.
* Improved end-to-end acceptance-gate diagnostics to report rebuild
results accurately.
* **Documentation**
* Refined in-product guidance around how endpoint selection and
`pinEndpoint`/`endpointUrl` are determined after validation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Carlos Villela <cvillela@nvidia.com>
@cv cv added the v0.0.69 label Jun 27, 2026
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
## Summary
- Add explicit trusted metadata flags for compatible custom provider
switches: endpoint URL, credential env, and inference API.
- Persist explicit metadata into sandbox registry and matching onboard
session during inference set.
- Update OpenClaw/Hermes Anthropic inference-switch E2Es to pass mock
endpoint metadata instead of relying on unrelated session state.

## Why
Nightly openclaw-anthropic-inference-switch-e2e and
hermes-anthropic-inference-switch-e2e fail after PR NVIDIA#5869 because the
new source-boundary guard correctly refuses cross-provider
compatible-Anthropic switches without durable endpoint metadata. This PR
keeps that guard intact while giving the switch command a first-class
trusted metadata path.

## Validation
- npm run build:cli
- npm test -- src/lib/actions/inference-set.test.ts
src/commands/global-oclif-command-adapters.test.ts

## Related
- Regression from PR NVIDIA#5869


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added optional `--endpoint-url`, `--credential-env`, and
`--inference-api` flags to the Hermes/NemoClaw “inference set” commands.
* **Bug Fixes**
* Enhanced compatible-provider switching by validating allowed
`--inference-api` values, persisting durable rebuild metadata, and
synchronizing onboarding settings (including `endpoint-url`
normalization).
* **Documentation**
* Updated command references and compatibility guidance, including
trusted `--endpoint-url` requirements and allowed `--inference-api`
values.
* **Tests**
* Expanded unit and end-to-end scenarios to cover the new flags and
compatible switch behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
## Summary
- preserve the validated recreate endpoint in rebuild resume config even
when the existing session matches the sandbox name
- overwrite the resume session endpoint before `onboard --resume` so
stale-recovery retries cannot reuse an old/partial session endpoint
- point `double-onboard-e2e` stale rebuild diagnostics at the actual
rebuild output

## Context
Follow-up to PR NVIDIA#5869 and issue NVIDIA#4497 after `double-onboard-e2e` showed
stale rebuild recovery still recreating the wrong sandbox path / hiding
the actual rebuild output.

## Validation
- `npm run build:cli`
- `npm test -- src/lib/actions/sandbox/rebuild-resume-config.test.ts
src/lib/onboard/sandbox-registration.test.ts test/registry.test.ts
src/lib/actions/inference-set.test.ts
src/lib/actions/sandbox/rebuild-gateway-drift.test.ts`
- `bash -n test/e2e/test-double-onboard.sh`

Note: local commit/push hooks were attempted; the long-running hook
process was killed by the harness (signal 9), so commit/push used
`--no-verify` after the focused validation above passed.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Strengthened sandbox rebuild/resume so `onboard --resume` consistently
uses the validated recreate endpoint, avoiding stale
session/provider/model data from steering recovery.
* Added stricter, fail-closed custom-endpoint handling with URL
canonicalization and correct precedence when durable registry metadata
is available.
* Enforced env-driven, target-scoped endpoint selection/validation
(rejecting invalid, mismatched, or unsupported URLs).
* **Tests**
* Expanded rebuild/resume coverage across matching, stale, non-matching,
missing, and invalid custom-endpoint scenarios.
* Improved end-to-end acceptance-gate diagnostics to report rebuild
results accurately.
* **Documentation**
* Refined in-product guidance around how endpoint selection and
`pinEndpoint`/`endpointUrl` are determined after validation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: inference Inference routing, serving, model selection, or outputs area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants