Skip to content

fix(sandbox): recover gateway before maintenance sandbox-list retry - #4106

Merged
cv merged 2 commits into
mainfrom
codex/fix-3986-backup-gateway-recovery
May 23, 2026
Merged

fix(sandbox): recover gateway before maintenance sandbox-list retry#4106
cv merged 2 commits into
mainfrom
codex/fix-3986-backup-gateway-recovery

Conversation

@ericksoa

@ericksoa ericksoa commented May 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a shared openshell sandbox list wrapper that recovers the named NemoClaw OpenShell gateway and retries once when the initial list command fails without a known gateway-drift/schema mismatch
  • use the retry wrapper from backup-all, upgrade-sandboxes, and rebuild's pre-backup liveness check
  • keep gateway image drift and protobuf/schema mismatch paths fail-closed before recovery so they are not treated as stopped sandboxes

Fixes #3986.

Validation

  • npm run build:cli
  • npx vitest run src/lib/actions/gateway-drift-preflight.test.ts src/lib/actions/sandbox/rebuild-gateway-drift.test.ts src/lib/actions/global.test.ts src/commands/global-oclif-command-adapters.test.ts
  • npm run typecheck:cli
  • npm run checks
  • npx @biomejs/biome check src/lib/openshell-sandbox-list.ts src/lib/actions/maintenance.ts src/lib/actions/upgrade-sandboxes.ts src/lib/actions/sandbox/rebuild.ts src/lib/actions/gateway-drift-preflight.test.ts src/lib/actions/sandbox/rebuild-gateway-drift.test.ts src/lib/actions/global.ts src/lib/actions/global.test.ts src/commands/backup-all.ts
  • git diff --check

Summary by CodeRabbit

  • Bug Fixes

    • Backup operations now wait for completion before returning.
    • Recovery now retries sandbox-list queries when transient gateway/connectivity issues occur and avoids recovery for non-recoverable failures.
  • Improvements

    • Richer failure diagnostics that indicate whether gateway recovery was attempted and succeeded.
    • Rebuild/upgrade flows now integrate gateway-recovery-aware sandbox listing for more reliable operations.

Review Change Stack

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@ericksoa ericksoa added bug NV QA Bugs found by the NVIDIA QA Team UAT Issues flagged for User Acceptance Testing. labels May 23, 2026
@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a gateway-recovery wrapper for OpenShell sandbox-list queries, makes backup/rebuild/upgrade flows use it (and await recovery where needed), extends the recover API to accept recoverable states, and updates tests to assert recovery and non-recovery behaviors.

Changes

Gateway Recovery with Retry Logic

Layer / File(s) Summary
Gateway recovery infrastructure module
src/lib/openshell-sandbox-list.ts
New module exports captureSandboxListWithGatewayRecovery() and printSandboxListFailureWithRecoveryContext(), returning {result, recoveryAttempted, recoverySucceeded}.
Gateway runtime API: recoverable states option
src/lib/gateway-runtime-action.ts
recoverNamedGatewayRuntime(options?) accepts optional recoverableStates and uses that set when deciding whether to attempt recovery.
Action dispatcher with async propagation
src/lib/actions/global.ts, src/lib/actions/global.test.ts
runBackupAllAction() converted to async and awaits executeBackupAllAction(); imports reorganized and test now awaits the action.
CLI command integration
src/commands/backup-all.ts
BackupAllCommand.run() now awaits runBackupAllAction() so the CLI returns after the action completes.
Backup action with gateway recovery
src/lib/actions/maintenance.ts
backupAll() becomes async and uses captureSandboxListWithGatewayRecovery(); failure printing uses recovery-context printer.
Sandbox rebuild with gateway recovery
src/lib/actions/sandbox/rebuild.ts
Rebuild preflight uses captureSandboxListWithGatewayRecovery() and prints recovery-context diagnostics on sandbox-list failure.
Sandbox upgrade with gateway recovery
src/lib/actions/upgrade-sandboxes.ts
upgradeSandboxes() uses captureSandboxListWithGatewayRecovery() and prints recovery-context diagnostics on failure.
Gateway-drift preflight tests (backup & upgrade)
src/lib/actions/gateway-drift-preflight.test.ts
Tests updated to spy on recoverNamedGatewayRuntime, use async rejection assertions, and verify recovery and non-recovery scenarios (including retry count and expected recoverableStates).
Rebuild gateway-drift tests
src/lib/actions/sandbox/rebuild-gateway-drift.test.ts
Expanded mocks/spies and assertions to validate recovery invocation, retry behavior, and negative paths for generic sandbox-list failures.
Inference tests: deterministic docker shim
src/lib/inference/local.test.ts
Suite-level beforeAll/afterAll create/remove a temp fake docker and reset the Ollama container port cache for deterministic tests.

Sequence Diagram(s):

sequenceDiagram
  participant Caller as maintenance/upgrade/rebuild
  participant Capture as captureSandboxListWithGatewayRecovery
  participant OpenShell as captureOpenshell
  participant Gateway as recoverNamedGatewayRuntime

  Caller->>Capture: request sandbox list
  Capture->>OpenShell: captureOpenshell(["sandbox","list"])
  OpenShell-->>Capture: initial result
  alt recoverable failure detected
    Capture->>Gateway: recoverNamedGatewayRuntime({recoverableStates})
    Gateway-->>Capture: recovered? (true/false)
    alt recovered == true
      Capture->>OpenShell: captureOpenshell(["sandbox","list"]) (retry)
      OpenShell-->>Capture: retried result
    end
  end
  Capture-->>Caller: { result, recoveryAttempted, recoverySucceeded }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related issues

Suggested labels

NemoClaw CLI, Integration: OpenClaw

Suggested reviewers

  • jyaunches
  • cv

"🐰 I nudged the gateway awake at dawn,
retied the shells where retries had gone,
backups hum softly, no cryptic alarm,
sandboxes safe, in recovery's warm charm.
Hop, hop — code healed; the meadow sleeps on."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% 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 PR title accurately summarizes the main change: adding gateway recovery before sandbox-list retries during maintenance operations.
Linked Issues check ✅ Passed The PR implements automatic gateway recovery detection and retry logic for sandbox-list queries, directly addressing issue #3986's requirement for auto-recovery on dead gateway detection.
Out of Scope Changes check ✅ Passed All changes are focused on implementing gateway recovery for sandbox-list operations; no unrelated modifications were introduced.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-3986-backup-gateway-recovery

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

@github-actions

github-actions Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor

Findings: 1 needs attention, 0 worth checking, 0 nice ideas
Since last review: 0 prior items resolved, 0 still apply, 1 new item found

Review findings

🛠️ Needs attention

  • Extract or offset local.test.ts monolith growth (src/lib/inference/local.test.ts:38): This PR adds 37 lines to an existing large test file. The gathered monolith signal marks this as a current large-file hotspot with blocker severity because the file grew by 20 or more lines. The added fake-docker PATH setup is useful test scaffolding, but landing it in the monolith increases future maintenance cost.
    • Recommendation: Move the new Docker-runtime test fixture/setup into a focused helper or smaller test file, or offset the growth with equivalent extraction from src/lib/inference/local.test.ts before merge.
    • Evidence: monolithDeltas reports src/lib/inference/local.test.ts baseLines=748, headLines=785, delta=37, severity=blocker. The diff adds beforeAll/afterAll fake docker setup and imports in this file.

🔎 Worth checking

  • None.

🌱 Nice ideas

  • None.
Since last review details

Current findings:

  • Extract or offset local.test.ts monolith growth (src/lib/inference/local.test.ts:38): This PR adds 37 lines to an existing large test file. The gathered monolith signal marks this as a current large-file hotspot with blocker severity because the file grew by 20 or more lines. The added fake-docker PATH setup is useful test scaffolding, but landing it in the monolith increases future maintenance cost.
    • Recommendation: Move the new Docker-runtime test fixture/setup into a focused helper or smaller test file, or offset the growth with equivalent extraction from src/lib/inference/local.test.ts before merge.
    • Evidence: monolithDeltas reports src/lib/inference/local.test.ts baseLines=748, headLines=785, delta=37, severity=blocker. The diff adds beforeAll/afterAll fake docker setup and imports in this file.

Workflow run details

This is an automated advisory review. A human maintainer must make the final merge decision.

@github-actions

github-actions Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: gateway-drift-preflight-e2e, upgrade-stale-sandbox-e2e, rebuild-openclaw-e2e, openshell-gateway-upgrade-e2e
Optional E2E: sandbox-survival-e2e, sandbox-operations-e2e, rebuild-hermes-e2e

Auto-dispatched E2E: upgrade-stale-sandbox-e2e, rebuild-openclaw-e2e, openshell-gateway-upgrade-e2e via nightly-e2e.yaml at 38fd5281de161614328401fbf5972ad337eccdfdnightly run

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • gateway-drift-preflight-e2e (low): Directly covers the backup-all fail-closed gateway drift/protobuf mismatch path that this PR modifies while introducing sandbox-list recovery.
  • upgrade-stale-sandbox-e2e (high): Exercises nemoclaw upgrade-sandboxes --check and subsequent rebuild of a stale sandbox, covering the changed live sandbox-list query and rebuild orchestration.
  • rebuild-openclaw-e2e (high): Covers the changed rebuild liveness check before backup/delete/recreate and verifies user workspace state survives rebuild.
  • openshell-gateway-upgrade-e2e (high): Validates the real OpenShell gateway upgrade path with pre-upgrade backup and restored sandbox state, which is sensitive to the backup-all async/recovery changes.

Optional E2E

  • sandbox-survival-e2e (medium): Useful adjacent confidence for non-destructive gateway stop/start recovery and live inference after gateway lifecycle disruption.
  • sandbox-operations-e2e (high): Broad sandbox lifecycle coverage including sandbox list/status, registry recovery, and gateway kill recovery; helpful for the new sandbox-list recovery helper but not as targeted as the required jobs.
  • rebuild-hermes-e2e (high): Optional agent-variant confidence for the same generic rebuild liveness/backup path with Hermes-specific state.

New E2E recommendations

  • OpenShell sandbox-list recovery (high): Existing E2E covers gateway drift fail-closed behavior and general gateway recovery, but does not specifically simulate openshell sandbox list returning a recoverable connection/refused/no-active-gateway error and then verify backup-all, upgrade-sandboxes, and rebuild retry after named-gateway recovery.
    • Suggested test: Add a focused E2E/regression job that fakes or induces a transient sandbox-list gateway connectivity failure, asserts NemoClaw attempts named-gateway recovery, retries openshell sandbox list, and proceeds only after a successful retry for backup-all, upgrade-sandboxes --check, and <sandbox> rebuild --yes.

@github-actions

github-actions Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

E2E Scenario Advisor Recommendation

Required scenario E2E: None
Optional scenario E2E: None

Workflow run

Full scenario advisor summary

E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required scenario E2E

  • None. No scenario workflow, scenario metadata, scenario runtime, or validation-suite files changed.

Optional scenario E2E

  • None.

Relevant changed files

  • None.

@ericksoa ericksoa changed the title Recover OpenShell gateway before maintenance sandbox list retry fix(sandbox): recover gateway before maintenance sandbox-list retry May 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26318311620
Target ref: bf7579708df4dcaf5a1050ea0d119c23fc87ae68
Workflow ref: main
Requested jobs: rebuild-openclaw-e2e,upgrade-stale-sandbox-e2e,openshell-gateway-upgrade-e2e
Summary: 3 passed, 0 failed, 0 skipped

Job Result
openshell-gateway-upgrade-e2e ✅ success
rebuild-openclaw-e2e ✅ success
upgrade-stale-sandbox-e2e ✅ success

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/openshell-sandbox-list.ts (1)

33-44: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Propagate the actual recovery-attempt status instead of hardcoding it.

recoveryAttempted is currently forced to true once Line 33 is reached, even when recoverNamedGatewayRuntime() returns attempted: false (e.g., filtered by recoverableStates). That can print misleading recovery diagnostics downstream.

🔧 Proposed fix
   const recovery = await recoverNamedGatewayRuntime({
     recoverableStates: ["missing_named", "named_unhealthy", "named_unreachable"],
   });
   if (!recovery.recovered) {
-    return { result: initial, recoveryAttempted: true, recoverySucceeded: false };
+    return {
+      result: initial,
+      recoveryAttempted: recovery.attempted,
+      recoverySucceeded: false,
+    };
   }

   return {
     result: captureOpenshell(["sandbox", "list"]),
-    recoveryAttempted: true,
-    recoverySucceeded: true,
+    recoveryAttempted: recovery.attempted,
+    recoverySucceeded: recovery.attempted && recovery.recovered,
   };
 }
🤖 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/openshell-sandbox-list.ts` around lines 33 - 44, The code hardcodes
recoveryAttempted: true after calling recoverNamedGatewayRuntime(); update both
return sites to use the actual flag from the recovery object instead of true —
i.e., replace the literal true with recovery.attempted (keep recoverySucceeded
using recovery.recovered and preserve result values: initial on failure and
captureOpenshell(["sandbox","list"]) on success) so the
recoverNamedGatewayRuntime(), recovery.attempted, recovery.recovered,
captureOpenshell, and initial symbols correctly propagate the real attempt
status.
🤖 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.

Outside diff comments:
In `@src/lib/openshell-sandbox-list.ts`:
- Around line 33-44: The code hardcodes recoveryAttempted: true after calling
recoverNamedGatewayRuntime(); update both return sites to use the actual flag
from the recovery object instead of true — i.e., replace the literal true with
recovery.attempted (keep recoverySucceeded using recovery.recovered and preserve
result values: initial on failure and captureOpenshell(["sandbox","list"]) on
success) so the recoverNamedGatewayRuntime(), recovery.attempted,
recovery.recovered, captureOpenshell, and initial symbols correctly propagate
the real attempt status.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 40cb3cc6-9e6e-4389-838e-447d516fd4f2

📥 Commits

Reviewing files that changed from the base of the PR and between bf75797 and 38fd528.

📒 Files selected for processing (5)
  • src/lib/actions/gateway-drift-preflight.test.ts
  • src/lib/actions/sandbox/rebuild-gateway-drift.test.ts
  • src/lib/gateway-runtime-action.ts
  • src/lib/inference/local.test.ts
  • src/lib/openshell-sandbox-list.ts

@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26318968280
Target ref: 38fd5281de161614328401fbf5972ad337eccdfd
Workflow ref: main
Requested jobs: upgrade-stale-sandbox-e2e,rebuild-openclaw-e2e,openshell-gateway-upgrade-e2e
Summary: 3 passed, 0 failed, 0 skipped

Job Result
openshell-gateway-upgrade-e2e ✅ success
rebuild-openclaw-e2e ✅ success
upgrade-stale-sandbox-e2e ✅ success

@ericksoa
ericksoa requested a review from cv May 23, 2026 01:13
@cv
cv merged commit 29ee14d into main May 23, 2026
28 checks passed
@wscurran wscurran added area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery bug-fix PR fixes a bug or regression platform: wsl Affects Windows Subsystem for Linux and removed priority: high labels Jun 3, 2026
@cv
cv deleted the codex/fix-3986-backup-gateway-recovery branch June 28, 2026 00:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery bug-fix PR fixes a bug or regression NV QA Bugs found by the NVIDIA QA Team platform: wsl Affects Windows Subsystem for Linux UAT Issues flagged for User Acceptance Testing.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[WSL2][Sandbox] openshell-docker-gateway host daemon shuts down on idle, breaks subsequent install.sh upgrade backup step

3 participants