Skip to content

fix(sandbox): recover relaunches a restart-killed gateway supervisor - #6677

Merged
cv merged 14 commits into
mainfrom
fix/6635-gateway-recovery-after-restart
Jul 12, 2026
Merged

fix(sandbox): recover relaunches a restart-killed gateway supervisor#6677
cv merged 14 commits into
mainfrom
fix/6635-gateway-recovery-after-restart

Conversation

@laitingsheng

@laitingsheng laitingsheng commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

After a local Docker-driver sandbox container restart, legacy containers whose persisted startup command was sleep infinity lost the nemoclaw-start workload session. recover now handles only a root-controller-attested, stable no-supervisor state by transactionally recreating the registered container with a credential-free managed startup command. NemoClaw retains the previous container until the replacement passes container-pinned managed-control health and settle checks; otherwise it attempts rollback and returns rebuild or re-onboard guidance.

Related Issue

Fixes #6635

Changes

  • Added the dedicated SUPERVISOR_NOT_RUNNING controller result. It is emitted only after two complete zero-supervisor scans with unchanged PID 1 and no unreadable, ambiguous, or changing process state. Those cases remain SUPERVISOR_UNAVAILABLE and cannot authorize container mutation.
  • Replaced the ordinary sandbox-exec background launch with a host-side container transaction. Recovery pins the registered container identity, verifies the legacy sleep infinity startup, uses the immutable image identity, and persists env ... nemoclaw-start as the managed startup command.
  • Reconstructs only non-credential runtime environment values. Credential placeholders, credential-bearing proxy URLs, and secret-shaped diagnostics are omitted or redacted.
  • Retains the previous container for rollback. The replacement is probed through root managed control pinned to its container ID; recovery commits only after managed gateway health and the settle check pass.
  • Keeps SUPERVISOR_NOT_RUNNING distinct from privileged-control failures and prints non-circular rebuild or re-onboard guidance when trusted recovery cannot complete.
  • Added unit and integration coverage for stable absence, ambiguity and race refusal, container identity pinning, immutable-image recreation, invalid startup-command refusal, credential exclusion, rollback, commit-after-health, and sanitized diagnostics.
  • Extended gateway-guard-recovery with a real Docker container restart. It verifies container replacement, managed supervisor topology, forwarded health, credential exclusion, and a successful agent inference request after recovery.
  • Updated lifecycle, command-reference, and troubleshooting documentation for the transactional recovery boundary and writable-layer limitation.

Verification Evidence

  • Final-head PR CI: run 29178402069 passed all eight CLI shards, type checking, static checks, plugin and installer tests, E2E support, and the remaining required non-live jobs.
  • Focused container/recovery unit matrix: 17 files and 187 tests passed.
  • Focused managed-controller/recovery integration matrix: 2 files and 8 tests passed.
  • Additional recovery/controller integration matrix: 122 tests passed during the implementation review.
  • E2E support project: 116 files and 946 tests passed; live/fast parity passed.
  • npm run check:diff: all applicable pre-commit, commit-message, secret-scan, repository, and pre-push checks passed.
  • Normal pre-push hooks: plugin TypeScript, checked-JavaScript build, CLI TypeScript, and version synchronization passed.
  • npm run docs: passed with 0 errors; two pre-existing hidden-page warnings remain.
  • Local broad integration was attempted but is not claimed as a pass: the shared host has an occupied port required by an unchanged onboarding test, and the isolated worktree's temporary dependency symlink is intentionally rejected by an unchanged trusted-path guard. The affected tests pass when those environmental constraints are removed. PR CI remains authoritative.
  • Final-head live gateway-guard-recovery: run 29178405818 passed 1/1. Recovery exited 0 without timing out, proved one managed supervisor under PID 1, restored forward health with HTTP 200, and completed live inference with the expected answer. Artifact.
  • Final-head automatic release gate: run 29178569987 passed both onboard-repair and onboard-resume.
  • Adjacent live targets on production commit a89859bb5 passed: gpu-e2e, credential-sanitization, rebuild-openclaw, sandbox-operations, and cloud-onboard. Final commit 2c57e7ea2 changes only the live topology test UID assertion.

Type of Change

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

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification:
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: maintainer security review found no remaining code blocker; Terra reports merge_as_is with zero findings, and the final-head live recovery proof passed.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Verification

  • PR description includes the DCO sign-off declaration and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run check:diff passed when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result: focused recovery matrix 149 passed after the readiness and forward changes; focused container/recovery 187 passed; focused controller/recovery integration 8 passed; E2E support 946 passed; final-head live gateway recovery 1/1 passed.
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result: final-head PR CI and E2E / PR Gate passed; local broad-run limitations remain documented above.
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without new warnings (doc changes only) — 0 errors; two pre-existing hidden-page warnings unchanged.
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Tinson Lai tinsonl@nvidia.com
Signed-off-by: Carlos Villela cvillela@nvidia.com

Summary by CodeRabbit

  • New Features
    • Added a trusted legacy recovery path for supported local Docker sandboxes when the managed supervisor isn’t running.
    • Added a new lifecycle behavior flag to disable automatic supervisor relaunch during recovery.
  • Bug Fixes
    • Improved gateway restart failure classification (including a distinct “supervisor not running” outcome) and corresponding recovery hints.
    • Strengthened safeguards to prevent recovery when container identity changes, and improved Docker rollback/restore behavior when results are incomplete.
    • Added validation to prevent privileged execution when the expected container identity doesn’t match.
  • Documentation
    • Expanded recovery and troubleshooting guidance for supervisor-not-running scenarios and the disable-relaunch flag.
  • Tests
    • Added/updated coverage for supervisor relaunch recovery decisions and Docker redaction/patch edge cases.

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
@laitingsheng laitingsheng self-assigned this Jul 11, 2026
@coderabbitai

coderabbitai Bot commented Jul 11, 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

Managed recovery now distinguishes a missing in-sandbox supervisor, reconstructs a credential-free startup environment, performs pinned transactional container recreation, validates managed gateway readiness, and documents rollback and fallback behavior.

Changes

Supervisor Relaunch Recovery

Layer / File(s) Summary
Supervisor discovery and failure classification
scripts/managed-gateway-control.py, src/lib/actions/sandbox/gateway-restart.ts, test/managed-gateway-control.test.ts
Distinguishes absent and inconclusive supervisors and exposes SUPERVISOR_NOT_RUNNING as a dedicated failure layer.
Credential-safe startup environment
src/lib/onboard/sandbox-create-launch.ts, src/lib/onboard/sandbox-create-launch.test.ts
Centralizes runtime environment construction and omits credential-bearing proxy and placeholder values when requested.
Pinned transactional container recreation
src/lib/onboard/docker-gpu-patch.ts, src/lib/onboard/docker-startup-command-patch.ts, src/lib/onboard/*test.ts
Validates immutable image and container identity, recreates containers with rollback handling, and uses strict Docker result validation.
Managed recovery orchestration
src/lib/actions/sandbox/process-recovery.ts, src/lib/actions/sandbox/supervisor-relaunch.ts, test/process-recovery-supervisor-relaunch.test.ts, src/lib/actions/sandbox/supervisor-relaunch.test.ts
Attempts supervisor relaunch for the missing-supervisor layer, propagates tri-state outcomes, performs pinned probes, and finalizes or rolls back recovery.
Pinned execution and recovery validation
src/lib/sandbox/privileged-exec.ts, src/lib/sandbox/privileged-exec.test.ts, test/e2e/live/gateway-guard-recovery.test.ts, test/e2e/mock-parity.json
Rejects changed container identities and adds unit, integration, end-to-end, and parity coverage for recovery paths.
Recovery lifecycle documentation
docs/manage-sandboxes/lifecycle.mdx, docs/reference/commands.mdx, docs/reference/troubleshooting.mdx
Documents transactional recreation, mounted-state preservation, writable-layer behavior, fallback remediation, dashboard binding, and the disable flag.

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

Sequence Diagram(s)

sequenceDiagram
  participant checkAndRecoverSandboxProcesses
  participant relaunchManagedSupervisorSession
  participant Docker
  participant ManagedGateway
  checkAndRecoverSandboxProcesses->>relaunchManagedSupervisorSession: handle SUPERVISOR_NOT_RUNNING
  relaunchManagedSupervisorSession->>Docker: recreate pinned legacy container
  Docker-->>relaunchManagedSupervisorSession: replacement container
  relaunchManagedSupervisorSession->>ManagedGateway: probe supervisor and gateway health
  ManagedGateway-->>relaunchManagedSupervisorSession: readiness result
  relaunchManagedSupervisorSession-->>checkAndRecoverSandboxProcesses: finalize commit or rollback
Loading

Possibly related PRs

  • NVIDIA/NemoClaw#1273: The relaunch startup command depends on the env ... nemoclaw-start bootstrap wrapper.

Suggested labels: VDR, platform: container

Suggested reviewers: jyaunches, ericksoa, cv, brandonpelfrey

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Linked Issues check ✅ Passed The PR implements a managed recovery path for restart-killed supervisors and gateway restoration, which addresses #6635's dead-end recovery behavior.
Out of Scope Changes check ✅ Passed The changes appear aligned with the recovery fix, its supporting safeguards, docs, and tests, with no clearly unrelated additions.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: sandbox recovery now relaunches a supervisor after a container restart.
✨ 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 fix/6635-gateway-recovery-after-restart

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

@laitingsheng laitingsheng removed their assignment Jul 11, 2026
@github-code-quality

github-code-quality Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage remains at 96%, unchanged from the main branch.

TypeScript / code-coverage/cli

The overall coverage in the fix/6635-gateway-rec... branch remains at 79%, unchanged from the main branch.

Show a code coverage summary of the most impacted files.
File main 451f6ab fix/6635-gateway-rec... 2c57e7e +/-
src/lib/sandbox/config.ts 72% 59% -13%
src/lib/shields/index.ts 70% 59% -11%
src/lib/onboard...er-gpu-patch.ts 80% 76% -4%
src/lib/shields...nsition-lock.ts 85% 89% +4%
src/lib/messagi...agent-config.ts 64% 69% +5%
src/lib/agent/onboard.ts 70% 80% +10%
src/lib/actions...ess-recovery.ts 71% 82% +11%
src/lib/onboard...tup-nim-flow.ts 80% 94% +14%
src/lib/onboard...host-forward.ts 45% 100% +55%
src/lib/actions...sor-relaunch.ts 0% 67% +67%

Updated July 12, 2026 03:39 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

Copy link
Copy Markdown
Contributor

@laitingsheng laitingsheng added NV QA Bugs found by the NVIDIA QA Team area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery bug-fix PR fixes a bug or regression and removed NV QA Bugs found by the NVIDIA QA Team labels Jul 11, 2026
@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: onboard-resume, onboard-repair, gateway-guard-recovery, cloud-onboard
Optional E2E: dashboard-remote-bind

Dispatch hint: onboard-resume,onboard-repair,gateway-guard-recovery,cloud-onboard,dashboard-remote-bind

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • onboard-resume: Required deterministic lifecycle-state validation: persisted onboarding and live sandbox state must converge after retries and recovery.
  • onboard-repair: Required deterministic lifecycle-state validation for repair convergence, cleanup, and live runtime status.
  • gateway-guard-recovery: Exercises the changed live privileged gateway recovery path, including supervisor guards and recovery behavior for a real sandbox.
  • cloud-onboard: Docker sandbox recreation/startup-command and runtime launch changes can affect the complete hosted onboarding flow.

Optional E2E

  • dashboard-remote-bind: Useful adjacent coverage because forward recovery now changes forward start descriptor handling and bind-safe post-success validation.

New E2E recommendations

  • transactional supervisor relaunch (high): The live gateway guard test should explicitly prove legacy keepalive recovery end-to-end: recreate only after two stable absence scans, preserve mounted state, restore the old container on failed managed-health/settle proof, and remove it only after commit.
    • Suggested test: Extend the existing gateway-guard-recovery live coverage with a legacy keepalive container relaunch-and-rollback scenario.

Dispatch hint

  • Workflow: e2e.yaml
  • jobs input: onboard-resume,onboard-repair,gateway-guard-recovery,cloud-onboard,dashboard-remote-bind

@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: onboard-repair, onboard-resume
Optional E2E targets: None

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-repair
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-resume

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • onboard-repair: Onboarding and sandbox state must converge across persisted metadata, reported status, and the live runtime.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-repair
  • onboard-resume: Onboarding and sandbox state must converge across persisted metadata, reported status, and the live runtime.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=onboard-resume

Optional E2E targets

  • None.

Relevant changed files

  • src/lib/actions/sandbox/gateway-restart.ts
  • src/lib/actions/sandbox/process-recovery.ts
  • src/lib/actions/sandbox/supervisor-relaunch.ts
  • src/lib/onboard/sandbox-create-launch.ts

@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Changes requested

Merge posture: Do not merge yet
Primary next action: Fix PRA-1: Residual monolith growth in process-recovery.ts not offset by extraction; then add or justify PRA-T1.
Open items: 3 required · 6 warnings · 0 suggestions · 8 test follow-ups
Since last review: 2 prior items resolved · 8 still apply · 1 new item found

Action checklist

  • PRA-1 Fix: Residual monolith growth in process-recovery.ts not offset by extraction in src/lib/actions/sandbox/process-recovery.ts:1
  • PRA-2 Fix: Monolith growth in sandbox-create-launch.test.ts in src/lib/onboard/sandbox-create-launch.test.ts:1
  • PRA-4 Fix: Unmet acceptance: integration test for successful supervisor relaunch does not assert forwardRecovered: true in test/process-recovery-supervisor-relaunch.test.ts:245
  • PRA-3 Resolve or justify: NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH is a single-use config knob in src/lib/actions/sandbox/supervisor-relaunch.ts:34
  • PRA-5 Resolve or justify: Missing negative test: relaunch succeeds but forward recovery fails in test/process-recovery-supervisor-relaunch.test.ts:1
  • PRA-6 Resolve or justify: Silent registry-missing return in reconstructSupervisorLaunchEnvArgs loses diagnostic context in src/lib/actions/sandbox/supervisor-relaunch.ts:19
  • PRA-7 Resolve or justify: Shell command interpolation in daemonCommand creates theoretical injection surface in src/lib/actions/sandbox/supervisor-relaunch.ts:44
  • PRA-8 Resolve or justify: Bare catch in relaunchManagedSupervisorSession loses failure diagnostics in src/lib/actions/sandbox/supervisor-relaunch.ts:77
  • PRA-9 Resolve or justify: Missing integration test for state divergence: managed probe RUNNING but SSH probe STOPPED in test/process-recovery-supervisor-relaunch.test.ts:1
  • 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: Runtime validation
  • PRA-T6 Add or justify test follow-up: Missing integration test for state divergence: managed probe RUNNING but SSH probe STOPPED
  • PRA-T7 Add or justify test follow-up: Acceptance clause
  • PRA-T8 Add or justify test follow-up: supervisor-relaunch.ts:19 — reconstructSupervisorLaunchEnvArgs returns null on registry-missing

Findings index

ID Severity Category Location Required action
PRA-1 Required architecture src/lib/actions/sandbox/process-recovery.ts:1 Consider extracting remaining cohesive units (e.g., forward recovery orchestration, gateway health wait logic) or accept the current size with explicit justification.
PRA-2 Required architecture src/lib/onboard/sandbox-create-launch.test.ts:1 Consider extracting test helpers or splitting into focused test files per functional area (e.g., env-args, create-launch, prebuild).
PRA-3 Resolve/justify architecture src/lib/actions/sandbox/supervisor-relaunch.ts:34 Either remove the flag and document the escape hatch as 'set a constant to disable in source for troubleshooting', or add a second consumer (e.g., a test that verifies the disable path) to justify its existence.
PRA-4 Required acceptance test/process-recovery-supervisor-relaunch.test.ts:245 Add expect(result.forwardRecovered).toBe(true) to the integration test 'reaches a healthy recovery once the relaunched supervisor answers managed probes'.
PRA-5 Resolve/justify correctness test/process-recovery-supervisor-relaunch.test.ts:1 Add a test case mocking ensureSandboxPortForward to return false after successful relaunch and health probe, verifying the correct partial-failure return value.
PRA-6 Resolve/justify architecture src/lib/actions/sandbox/supervisor-relaunch.ts:19 Add a console.error or structured log when registry entry is missing, distinguishing this failure mode from supervisor relaunch execution failures.
PRA-7 Resolve/justify security src/lib/actions/sandbox/supervisor-relaunch.ts:44 Consider using spawn with array arguments instead of sh -c string, or add a comment justifying why shell interpolation is safe here given the controlled env source and shellQuote usage.
PRA-8 Resolve/justify security src/lib/actions/sandbox/supervisor-relaunch.ts:77 Capture the error in the catch block and log a sanitized diagnostic (e.g., error.code, error.message) before returning false, or return a structured failure reason.
PRA-9 Resolve/justify tests test/process-recovery-supervisor-relaunch.test.ts:1 Add an integration test mocking confirmRecoveredSandboxGatewayManaged to return true while isSandboxGatewayRunning returns false, verifying correct convergence behavior.

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-1 Required — Residual monolith growth in process-recovery.ts not offset by extraction

  • Location: src/lib/actions/sandbox/process-recovery.ts:1
  • Category: architecture
  • Problem: Despite extracting supervisor relaunch logic to supervisor-relaunch.ts (80 lines), process-recovery.ts grew by 28 lines (now 977). Growth comes from integration plumbing: onFailureLayer callback, managedRecoveryFailureLayer tracking, updated hint logic, and new import. This file remains the largest sandbox lifecycle module.
  • Impact: Increased cognitive load and maintenance burden on central sandbox lifecycle module; harder to review security-critical recovery paths in isolation.
  • Required action: Consider extracting remaining cohesive units (e.g., forward recovery orchestration, gateway health wait logic) or accept the current size with explicit justification.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check line count of src/lib/actions/sandbox/process-recovery.ts (currently 977 lines per diff stat).
  • Missing regression test: N/A — architectural finding; no regression test applies.
  • Done when: The required change is committed and verification passes: Check line count of src/lib/actions/sandbox/process-recovery.ts (currently 977 lines per diff stat).
  • Evidence: Monolith delta: process-recovery.ts +28 lines, now 977 Diff shows new onFailureLayer callback, managedRecoveryFailureLayer variable, updated printHostManagedGatewayRecoveryHints signature

PRA-2 Required — Monolith growth in sandbox-create-launch.test.ts

  • Location: src/lib/onboard/sandbox-create-launch.test.ts:1
  • Category: architecture
  • Problem: Test file grew by 30 lines (now 427) from a new describe block for buildSandboxRuntimeEnvArgs. While test additions are expected, this file is already a hotspot and growth compounds maintenance burden.
  • Impact: Test file becoming unwieldy; harder to locate and maintain specific test scenarios.
  • Required action: Consider extracting test helpers or splitting into focused test files per functional area (e.g., env-args, create-launch, prebuild).
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check line count of src/lib/onboard/sandbox-create-launch.test.ts (currently 427 lines per diff stat).
  • Missing regression test: N/A — architectural finding; no regression test applies.
  • Done when: The required change is committed and verification passes: Check line count of src/lib/onboard/sandbox-create-launch.test.ts (currently 427 lines per diff stat).
  • Evidence: Monolith delta: sandbox-create-launch.test.ts +30 lines, now 427 New describe('buildSandboxRuntimeEnvArgs') block added

PRA-4 Required — Unmet acceptance: integration test for successful supervisor relaunch does not assert forwardRecovered: true

Review findings by urgency: 3 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-3 Resolve/justify — NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH is a single-use config knob

  • Location: src/lib/actions/sandbox/supervisor-relaunch.ts:34
  • Category: architecture
  • Problem: The env flag NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH is checked only in one location (supervisor-relaunch.ts:34) and has no second consumer (e.g., a test that verifies the disable path). Integration test ci: auto-update release notes on push to main #1 stubs it but exercises the fallback path via the flag, not as a distinct disable-path test.
  • Impact: Single-use config knobs increase surface area without proportional value; a constant or source-level comment would be clearer until a second consumer exists.
  • Recommended action: Either remove the flag and document the escape hatch as 'set a constant to disable in source for troubleshooting', or add a second consumer (e.g., a test that verifies the disable path) to justify its existence.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search for NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH in the codebase — only one reference in supervisor-relaunch.ts:34.
  • Missing regression test: Add a dedicated test that exercises the disable path and verifies rebuild guidance is printed.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search for NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH in the codebase — only one reference in supervisor-relaunch.ts:34.
  • Evidence: supervisor-relaunch.ts:34: if (process.env.NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH === "1") return false; Integration test ci: auto-update release notes on push to main #1 stubs the flag but does not isolate the disable path as a distinct test case.

PRA-5 Resolve/justify — Missing negative test: relaunch succeeds but forward recovery fails

  • Location: test/process-recovery-supervisor-relaunch.test.ts:1
  • Category: correctness
  • Problem: No test covers the scenario where relaunchManagedSupervisorSession succeeds, health probe returns RUNNING, but ensureSandboxPortForward returns false. The code path at process-recovery.ts:589-600 handles this (returns recovered: true, forwardRecovered: false, forwardRecoveryFailed: true) but has no regression test.
  • Impact: Partial failure mode where gateway recovers but dashboard forward fails is untested; operator would see 'gateway restarted' but no dashboard access with no clear remediation.
  • Recommended action: Add a test case mocking ensureSandboxPortForward to return false after successful relaunch and health probe, verifying the correct partial-failure return value.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search test/process-recovery-supervisor-relaunch.test.ts for a test exercising ensureSandboxPortForward failure after relaunch — none exists.
  • Missing regression test: Add test: 'relaunch succeeds and health passes but forward recovery fails, returning recovered: true, forwardRecovered: false, forwardRecoveryFailed: true'.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search test/process-recovery-supervisor-relaunch.test.ts for a test exercising ensureSandboxPortForward failure after relaunch — none exists.
  • Evidence: process-recovery.ts:589-600: forward recovery failure path after successful relaunch test/process-recovery-supervisor-relaunch.test.ts: three tests cover disabled-relaunch, secret-free env, healthy recovery — none cover forward failure

PRA-6 Resolve/justify — Silent registry-missing return in reconstructSupervisorLaunchEnvArgs loses diagnostic context

  • Location: src/lib/actions/sandbox/supervisor-relaunch.ts:19
  • Category: architecture
  • Problem: reconstructSupervisorLaunchEnvArgs returns null when registry.getSandbox(sandboxName) returns undefined, with no diagnostic logging. The caller (relaunchManagedSupervisorSession) then returns false, making this failure mode indistinguishable from exec failures.
  • Impact: Operator cannot distinguish 'sandbox not registered' (registry inconsistency) from execution failures; remediation guidance differs (registry repair vs rebuild/re-onboard).
  • Recommended action: Add a console.error or structured log when registry entry is missing, distinguishing this failure mode from supervisor relaunch execution failures.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check supervisor-relaunch.ts:19 — returns null without logging; caller at line 37 returns false without distinction.
  • Missing regression test: Unit test in supervisor-relaunch.test.ts covers registry-missing return value but does not verify diagnostic logging.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check supervisor-relaunch.ts:19 — returns null without logging; caller at line 37 returns false without distinction.
  • Evidence: supervisor-relaunch.ts:19: if (!entry) return null; // no log supervisor-relaunch.ts:37: if (envArgs === null) return false; // no distinction from exec failure supervisor-relaunch.test.ts:36-42: test verifies return value but not logging

PRA-7 Resolve/justify — Shell command interpolation in daemonCommand creates theoretical injection surface

  • Location: src/lib/actions/sandbox/supervisor-relaunch.ts:44
  • Category: security
  • Problem: The daemonCommand string uses sh -c with shellQuote on env args from trusted registry/agent sources. While the data sources are controlled, the string interpolation pattern creates a theoretical shell injection surface if future changes introduce untrusted input.
  • Impact: If env args ever include user-controlled data, shell metacharacters could execute arbitrary commands inside the sandbox as the sandbox user.
  • Recommended action: Consider using spawn with array arguments instead of sh -c string, or add a comment justifying why shell interpolation is safe here given the controlled env source and shellQuote usage.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check supervisor-relaunch.ts:44-45 — daemonCommand builds a shell string with envPrefix and NEMOCLAW_START_PATH.
  • Missing regression test: N/A — security hardening; no regression test for theoretical surface.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check supervisor-relaunch.ts:44-45 — daemonCommand builds a shell string with envPrefix and NEMOCLAW_START_PATH.
  • Evidence: supervisor-relaunch.ts:44-45: const daemonCommand = `echo ${startedMarker}; ` + `setsid nohup env ${envPrefix} ${NEMOCLAW_START_PATH} ` + ">/tmp/nemoclaw-start-recover.log 2>&1 </dev/null &"; envArgs come from reconstructSupervisorLaunchEnvArgs which reads registry and agentRuntime — currently trusted sources.

PRA-8 Resolve/justify — Bare catch in relaunchManagedSupervisorSession loses failure diagnostics

  • Location: src/lib/actions/sandbox/supervisor-relaunch.ts:77
  • Category: security
  • Problem: The catch block at line 77 catches all errors from spawnSync and returns false without logging error.code, error.message, or any sanitized diagnostic. This makes troubleshooting exec failures (EACCES, timeout, ENOENT) harder for operators.
  • Impact: Operators see only 'recovery failed' without distinction between permission errors, missing binary, timeout, or other failure modes. Remediation guidance differs per failure mode.
  • Recommended action: Capture the error in the catch block and log a sanitized diagnostic (e.g., error.code, error.message) before returning false, or return a structured failure reason.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check supervisor-relaunch.ts:77-79 — catch block returns false with no logging.
  • Missing regression test: Unit test in supervisor-relaunch.test.ts covers throw path but does not verify diagnostic logging.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check supervisor-relaunch.ts:77-79 — catch block returns false with no logging.
  • Evidence: supervisor-relaunch.ts:77-79: } catch { return false; } supervisor-relaunch.test.ts:44-52: test mocks spawnSync to throw and verifies return false, but no logging assertion

PRA-9 Resolve/justify — Missing integration test for state divergence: managed probe RUNNING but SSH probe STOPPED

  • Location: test/process-recovery-supervisor-relaunch.test.ts:1
  • Category: tests
  • Problem: The lifecycle-state invariant 'status agrees with independently probed gateway and sandbox state' is not covered by any test. checkAndRecoverSandboxProcesses uses managedProbeImpl (confirmRecoveredSandboxGatewayManaged) for initial health check but falls back to SSH probe (isSandboxGatewayRunning) during wait. No test exercises the case where managed probe returns RUNNING but SSH probe returns STOPPED, which could indicate state divergence.
  • Impact: State divergence between managed and SSH probes could cause recovery to incorrectly report success or hang. Operators would see inconsistent status without clear remediation.
  • Recommended action: Add an integration test mocking confirmRecoveredSandboxGatewayManaged to return true while isSandboxGatewayRunning returns false, verifying correct convergence behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search test/process-recovery-supervisor-relaunch.test.ts for a test mocking both managedProbeImpl and probeImpl with conflicting results — none exists.
  • Missing regression test: Add test: 'managed probe reports RUNNING but SSH probe reports STOPPED, recovery handles divergence correctly'.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search test/process-recovery-supervisor-relaunch.test.ts for a test mocking both managedProbeImpl and probeImpl with conflicting results — none exists.
  • Evidence: process-recovery.ts:517-522: waitForRecoveredSandboxGateway called with managedProbeImpl for initialManagedHealthPassed, but probeImpl (SSH) as fallback test/process-recovery-supervisor-relaunch.test.ts: three tests mock health probe uniformly — none test probe divergence

💡 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 — Run the `onboard-repair` E2E job for Onboarding and sandbox state must converge across persisted metadata, reported status, and the live runtime. Matched files: `src/lib/actions/sandbox/gateway-restart.ts`, `src/lib/actions/sandbox/process-recovery.ts`, `src/lib/actions/sandbox/supervisor-relaunch.ts`, `src/lib/onboard/sandbox-create-launch.ts`.. Deterministic regression risks require live validation: lifecycle-state.
  • PRA-T2 Runtime validation — Run the `onboard-repair` E2E job for Onboarding and sandbox state must converge across persisted metadata, reported status, and the live runtime.. Deterministic regression risks require live validation: lifecycle-state.
  • PRA-T3 Runtime validation — Run the `onboard-resume` E2E job for Onboarding and sandbox state must converge across persisted metadata, reported status, and the live runtime. Matched files: `src/lib/actions/sandbox/gateway-restart.ts`, `src/lib/actions/sandbox/process-recovery.ts`, `src/lib/actions/sandbox/supervisor-relaunch.ts`, `src/lib/onboard/sandbox-create-launch.ts`.. Deterministic regression risks require live validation: lifecycle-state.
  • PRA-T4 Runtime validation — Run the `onboard-resume` E2E job for Onboarding and sandbox state must converge across persisted metadata, reported status, and the live runtime.. Deterministic regression risks require live validation: lifecycle-state.
  • PRA-T5 Runtime validation — Add unit test: reconstructSupervisorLaunchEnvArgs logs diagnostic on registry-missing. Deterministic regression risks require live validation: lifecycle-state.
  • PRA-T6 Missing integration test for state divergence: managed probe RUNNING but SSH probe STOPPED — Add an integration test mocking confirmRecoveredSandboxGatewayManaged to return true while isSandboxGatewayRunning returns false, verifying correct convergence behavior.
  • PRA-T7 Acceptance clause — At least one managed path relaunches the supervisor + gateway after a container restart — add test evidence or identify existing coverage. Integration test Change small local model to qwen3.5:9b #3 asserts recovered: true but not forwardRecovered: true; F-004 tracks missing assertion
  • PRA-T8 supervisor-relaunch.ts:19 — reconstructSupervisorLaunchEnvArgs returns null on registry-missing — Unit test in supervisor-relaunch.test.ts covers registry-missing return value but does not verify diagnostic logging. supervisor-relaunch.ts:19 returns null without logging; caller at line 37 returns false without distinction from exec failure
Since last review details

Current findings, using the urgency labels above:

PRA-1 Required — Residual monolith growth in process-recovery.ts not offset by extraction

  • Location: src/lib/actions/sandbox/process-recovery.ts:1
  • Category: architecture
  • Problem: Despite extracting supervisor relaunch logic to supervisor-relaunch.ts (80 lines), process-recovery.ts grew by 28 lines (now 977). Growth comes from integration plumbing: onFailureLayer callback, managedRecoveryFailureLayer tracking, updated hint logic, and new import. This file remains the largest sandbox lifecycle module.
  • Impact: Increased cognitive load and maintenance burden on central sandbox lifecycle module; harder to review security-critical recovery paths in isolation.
  • Required action: Consider extracting remaining cohesive units (e.g., forward recovery orchestration, gateway health wait logic) or accept the current size with explicit justification.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check line count of src/lib/actions/sandbox/process-recovery.ts (currently 977 lines per diff stat).
  • Missing regression test: N/A — architectural finding; no regression test applies.
  • Done when: The required change is committed and verification passes: Check line count of src/lib/actions/sandbox/process-recovery.ts (currently 977 lines per diff stat).
  • Evidence: Monolith delta: process-recovery.ts +28 lines, now 977 Diff shows new onFailureLayer callback, managedRecoveryFailureLayer variable, updated printHostManagedGatewayRecoveryHints signature

PRA-2 Required — Monolith growth in sandbox-create-launch.test.ts

  • Location: src/lib/onboard/sandbox-create-launch.test.ts:1
  • Category: architecture
  • Problem: Test file grew by 30 lines (now 427) from a new describe block for buildSandboxRuntimeEnvArgs. While test additions are expected, this file is already a hotspot and growth compounds maintenance burden.
  • Impact: Test file becoming unwieldy; harder to locate and maintain specific test scenarios.
  • Required action: Consider extracting test helpers or splitting into focused test files per functional area (e.g., env-args, create-launch, prebuild).
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check line count of src/lib/onboard/sandbox-create-launch.test.ts (currently 427 lines per diff stat).
  • Missing regression test: N/A — architectural finding; no regression test applies.
  • Done when: The required change is committed and verification passes: Check line count of src/lib/onboard/sandbox-create-launch.test.ts (currently 427 lines per diff stat).
  • Evidence: Monolith delta: sandbox-create-launch.test.ts +30 lines, now 427 New describe('buildSandboxRuntimeEnvArgs') block added

PRA-3 Resolve/justify — NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH is a single-use config knob

  • Location: src/lib/actions/sandbox/supervisor-relaunch.ts:34
  • Category: architecture
  • Problem: The env flag NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH is checked only in one location (supervisor-relaunch.ts:34) and has no second consumer (e.g., a test that verifies the disable path). Integration test ci: auto-update release notes on push to main #1 stubs it but exercises the fallback path via the flag, not as a distinct disable-path test.
  • Impact: Single-use config knobs increase surface area without proportional value; a constant or source-level comment would be clearer until a second consumer exists.
  • Recommended action: Either remove the flag and document the escape hatch as 'set a constant to disable in source for troubleshooting', or add a second consumer (e.g., a test that verifies the disable path) to justify its existence.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search for NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH in the codebase — only one reference in supervisor-relaunch.ts:34.
  • Missing regression test: Add a dedicated test that exercises the disable path and verifies rebuild guidance is printed.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search for NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH in the codebase — only one reference in supervisor-relaunch.ts:34.
  • Evidence: supervisor-relaunch.ts:34: if (process.env.NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH === "1") return false; Integration test ci: auto-update release notes on push to main #1 stubs the flag but does not isolate the disable path as a distinct test case.

PRA-4 Required — Unmet acceptance: integration test for successful supervisor relaunch does not assert forwardRecovered: true

PRA-5 Resolve/justify — Missing negative test: relaunch succeeds but forward recovery fails

  • Location: test/process-recovery-supervisor-relaunch.test.ts:1
  • Category: correctness
  • Problem: No test covers the scenario where relaunchManagedSupervisorSession succeeds, health probe returns RUNNING, but ensureSandboxPortForward returns false. The code path at process-recovery.ts:589-600 handles this (returns recovered: true, forwardRecovered: false, forwardRecoveryFailed: true) but has no regression test.
  • Impact: Partial failure mode where gateway recovers but dashboard forward fails is untested; operator would see 'gateway restarted' but no dashboard access with no clear remediation.
  • Recommended action: Add a test case mocking ensureSandboxPortForward to return false after successful relaunch and health probe, verifying the correct partial-failure return value.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search test/process-recovery-supervisor-relaunch.test.ts for a test exercising ensureSandboxPortForward failure after relaunch — none exists.
  • Missing regression test: Add test: 'relaunch succeeds and health passes but forward recovery fails, returning recovered: true, forwardRecovered: false, forwardRecoveryFailed: true'.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search test/process-recovery-supervisor-relaunch.test.ts for a test exercising ensureSandboxPortForward failure after relaunch — none exists.
  • Evidence: process-recovery.ts:589-600: forward recovery failure path after successful relaunch test/process-recovery-supervisor-relaunch.test.ts: three tests cover disabled-relaunch, secret-free env, healthy recovery — none cover forward failure

PRA-6 Resolve/justify — Silent registry-missing return in reconstructSupervisorLaunchEnvArgs loses diagnostic context

  • Location: src/lib/actions/sandbox/supervisor-relaunch.ts:19
  • Category: architecture
  • Problem: reconstructSupervisorLaunchEnvArgs returns null when registry.getSandbox(sandboxName) returns undefined, with no diagnostic logging. The caller (relaunchManagedSupervisorSession) then returns false, making this failure mode indistinguishable from exec failures.
  • Impact: Operator cannot distinguish 'sandbox not registered' (registry inconsistency) from execution failures; remediation guidance differs (registry repair vs rebuild/re-onboard).
  • Recommended action: Add a console.error or structured log when registry entry is missing, distinguishing this failure mode from supervisor relaunch execution failures.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check supervisor-relaunch.ts:19 — returns null without logging; caller at line 37 returns false without distinction.
  • Missing regression test: Unit test in supervisor-relaunch.test.ts covers registry-missing return value but does not verify diagnostic logging.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check supervisor-relaunch.ts:19 — returns null without logging; caller at line 37 returns false without distinction.
  • Evidence: supervisor-relaunch.ts:19: if (!entry) return null; // no log supervisor-relaunch.ts:37: if (envArgs === null) return false; // no distinction from exec failure supervisor-relaunch.test.ts:36-42: test verifies return value but not logging

PRA-7 Resolve/justify — Shell command interpolation in daemonCommand creates theoretical injection surface

  • Location: src/lib/actions/sandbox/supervisor-relaunch.ts:44
  • Category: security
  • Problem: The daemonCommand string uses sh -c with shellQuote on env args from trusted registry/agent sources. While the data sources are controlled, the string interpolation pattern creates a theoretical shell injection surface if future changes introduce untrusted input.
  • Impact: If env args ever include user-controlled data, shell metacharacters could execute arbitrary commands inside the sandbox as the sandbox user.
  • Recommended action: Consider using spawn with array arguments instead of sh -c string, or add a comment justifying why shell interpolation is safe here given the controlled env source and shellQuote usage.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check supervisor-relaunch.ts:44-45 — daemonCommand builds a shell string with envPrefix and NEMOCLAW_START_PATH.
  • Missing regression test: N/A — security hardening; no regression test for theoretical surface.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check supervisor-relaunch.ts:44-45 — daemonCommand builds a shell string with envPrefix and NEMOCLAW_START_PATH.
  • Evidence: supervisor-relaunch.ts:44-45: const daemonCommand = `echo ${startedMarker}; ` + `setsid nohup env ${envPrefix} ${NEMOCLAW_START_PATH} ` + ">/tmp/nemoclaw-start-recover.log 2>&1 </dev/null &"; envArgs come from reconstructSupervisorLaunchEnvArgs which reads registry and agentRuntime — currently trusted sources.

PRA-8 Resolve/justify — Bare catch in relaunchManagedSupervisorSession loses failure diagnostics

  • Location: src/lib/actions/sandbox/supervisor-relaunch.ts:77
  • Category: security
  • Problem: The catch block at line 77 catches all errors from spawnSync and returns false without logging error.code, error.message, or any sanitized diagnostic. This makes troubleshooting exec failures (EACCES, timeout, ENOENT) harder for operators.
  • Impact: Operators see only 'recovery failed' without distinction between permission errors, missing binary, timeout, or other failure modes. Remediation guidance differs per failure mode.
  • Recommended action: Capture the error in the catch block and log a sanitized diagnostic (e.g., error.code, error.message) before returning false, or return a structured failure reason.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check supervisor-relaunch.ts:77-79 — catch block returns false with no logging.
  • Missing regression test: Unit test in supervisor-relaunch.test.ts covers throw path but does not verify diagnostic logging.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check supervisor-relaunch.ts:77-79 — catch block returns false with no logging.
  • Evidence: supervisor-relaunch.ts:77-79: } catch { return false; } supervisor-relaunch.test.ts:44-52: test mocks spawnSync to throw and verifies return false, but no logging assertion

PRA-9 Resolve/justify — Missing integration test for state divergence: managed probe RUNNING but SSH probe STOPPED

  • Location: test/process-recovery-supervisor-relaunch.test.ts:1
  • Category: tests
  • Problem: The lifecycle-state invariant 'status agrees with independently probed gateway and sandbox state' is not covered by any test. checkAndRecoverSandboxProcesses uses managedProbeImpl (confirmRecoveredSandboxGatewayManaged) for initial health check but falls back to SSH probe (isSandboxGatewayRunning) during wait. No test exercises the case where managed probe returns RUNNING but SSH probe returns STOPPED, which could indicate state divergence.
  • Impact: State divergence between managed and SSH probes could cause recovery to incorrectly report success or hang. Operators would see inconsistent status without clear remediation.
  • Recommended action: Add an integration test mocking confirmRecoveredSandboxGatewayManaged to return true while isSandboxGatewayRunning returns false, verifying correct convergence behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search test/process-recovery-supervisor-relaunch.test.ts for a test mocking both managedProbeImpl and probeImpl with conflicting results — none exists.
  • Missing regression test: Add test: 'managed probe reports RUNNING but SSH probe reports STOPPED, recovery handles divergence correctly'.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search test/process-recovery-supervisor-relaunch.test.ts for a test mocking both managedProbeImpl and probeImpl with conflicting results — none exists.
  • Evidence: process-recovery.ts:517-522: waitForRecoveredSandboxGateway called with managedProbeImpl for initialManagedHealthPassed, but probeImpl (SSH) as fallback test/process-recovery-supervisor-relaunch.test.ts: three tests mock health probe uniformly — none test probe divergence

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

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — No blocking findings

Merge posture: No blocking advisor findings
Primary next action: No advisor follow-up required beyond maintainer review.
Findings: 0 required · 0 warnings · 0 optional suggestions
Since last review: 0 prior items resolved · 0 still apply · 0 new items found

Workflow run details

This is an automated review. Required findings need action before merge. Warnings and optional suggestions do not require a response or follow-up. A human maintainer makes the final merge decision.

@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

Caution

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

⚠️ Outside diff range comments (1)
src/lib/actions/sandbox/process-recovery.ts (1)

938-967: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Rebuild hint is skipped when relaunch "succeeds" but the gateway stays unhealthy.

managedRecoveryFailureLayer is captured from onFailureLayer even on the "relaunched" success path (it's set unconditionally before the relaunch attempt at lines 513-519). But the call to printHostManagedGatewayRecoveryHints reached when the post-relaunch health probe still fails (inside the recoveryKind !== null branch, around line 964) doesn't pass managedRecoveryFailureLayer, so it falls back to the generic "Retry the managed restart from the host" hint instead of the rebuild/re-onboard guidance — even though we already know the supervisor had to be relaunched. Since relaunch intentionally omits credentials, it's plausible the daemon starts but the gateway never becomes healthy, landing users back in the circular-guidance situation issue #6635 was meant to fix. This scenario is also not covered by test/process-recovery-supervisor-relaunch.test.ts (the second test exercises exactly this "relaunched but still STOPPED" case but only asserts on the spawned command, not the printed hints).

🐛 Proposed fix
     if (
       !waitForRecoveredSandboxGateway(sandboxName, {
         quiet,
         initialManagedHealthPassed: recoveryKind === "managed",
         timeoutSeconds: gatewayRecoveryTimeoutSeconds(recoveryAgent),
         managedProbeImpl: (name) =>
           confirmRecoveredSandboxGatewayManaged(name, {
             requestGatewaySupervisorActionImpl: requestGatewaySupervisorAction,
           }),
       })
     ) {
       if (!quiet) {
         console.error("  Gateway process started but is not responding.");
         printGatewayWedgeDiagnostics(sandboxName, executeSandboxExecCommand);
         console.error("  Check /tmp/gateway.log inside the sandbox for details.");
-        printHostManagedGatewayRecoveryHints(sandboxName, recoveryAgent);
+        printHostManagedGatewayRecoveryHints(sandboxName, recoveryAgent, managedRecoveryFailureLayer);
       }

Note: the specialized hint's wording ("cannot relaunch it") may need a small tweak to also fit the "relaunch started but gateway never became healthy" case.

Also applies to: 1022-1025

🤖 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/sandbox/process-recovery.ts` around lines 938 - 967, Pass the
captured managedRecoveryFailureLayer into printHostManagedGatewayRecoveryHints
in both unhealthy-gateway paths, including the post-relaunch health-check
failure and the corresponding later branch around the recovery result handling.
Update the specialized hint wording if needed so it accurately covers a relaunch
that started but left the gateway unhealthy, while preserving the existing
generic guidance for cases without a managed failure layer.
🤖 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 `@docs/manage-sandboxes/lifecycle.mdx`:
- Around line 233-234: Replace the em dashes in both lifecycle documentation
copies, including the sentences describing supervisor recovery and gateway
failure, with permitted punctuation such as commas or parentheses. Preserve the
existing meaning and command examples.

---

Outside diff comments:
In `@src/lib/actions/sandbox/process-recovery.ts`:
- Around line 938-967: Pass the captured managedRecoveryFailureLayer into
printHostManagedGatewayRecoveryHints in both unhealthy-gateway paths, including
the post-relaunch health-check failure and the corresponding later branch around
the recovery result handling. Update the specialized hint wording if needed so
it accurately covers a relaunch that started but left the gateway unhealthy,
while preserving the existing generic guidance for cases without a managed
failure layer.
🪄 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: 396b8197-d2cf-48c7-a83e-1511d9cdf1eb

📥 Commits

Reviewing files that changed from the base of the PR and between e4d2e91 and 945c42d.

📒 Files selected for processing (8)
  • docs/manage-sandboxes/lifecycle.mdx
  • docs/reference/commands.mdx
  • src/lib/actions/sandbox/gateway-restart.test.ts
  • src/lib/actions/sandbox/gateway-restart.ts
  • src/lib/actions/sandbox/process-recovery.ts
  • src/lib/onboard/sandbox-create-launch.test.ts
  • src/lib/onboard/sandbox-create-launch.ts
  • test/process-recovery-supervisor-relaunch.test.ts

Comment thread docs/manage-sandboxes/lifecycle.mdx Outdated

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

🧹 Nitpick comments (1)
src/lib/actions/sandbox/supervisor-relaunch.test.ts (1)

35-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a direct unit test for the success path.

Both tests here only cover failure branches (missing sandbox, transport throw). There's no direct test asserting relaunchManagedSupervisorSession returns true when spawnSync succeeds with the NEMOCLAW_SUPERVISOR_RELAUNCHED marker, nor a direct test of the NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH=1 short-circuit. These are exercised only indirectly through the heavier integration test in test/process-recovery-supervisor-relaunch.test.ts. A focused positive-path test here would pin down the core contract cheaply and independently of the integration flow.

As per path instructions, sandbox lifecycle behavior review requires tests to "cover failure, recovery, rebuild, and resume behavior without bypassing the public action boundary."

🤖 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/sandbox/supervisor-relaunch.test.ts` around lines 35 - 59,
Add focused unit coverage to the relaunchManagedSupervisorSession suite for the
successful spawnSync path, asserting it returns true when the output contains
NEMOCLAW_SUPERVISOR_RELAUNCHED. Also add a direct test for
NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH=1 confirming the action returns false
without invoking spawnSync, while retaining the existing failure-path tests.

Source: Path instructions

🤖 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/process-recovery-supervisor-relaunch.test.ts`:
- Around line 202-218: Update the spawnSync mock in the relaunch test to
distinguish calls by the documented observable contract or expected call order,
not the literal “nemoclaw-start” and “setsid” command text. Verify that the
HTTP_CODE=$(curl branch is exercised in this scenario and return output matching
the captured HTTP status expected by the code under test, removing or correcting
the STOPPED stub if unused. Keep isLocalForwardReachable and captureOpenshell
behavior intact while ensuring the test still exercises the supervisor recovery
path.
- Around line 185-189: Update the requireSource calls for openshellRuntime,
agentRuntime, registry, and forwardHealth to reference their .ts source modules
instead of .js paths; leave the unrelated childProcess import unchanged.

---

Nitpick comments:
In `@src/lib/actions/sandbox/supervisor-relaunch.test.ts`:
- Around line 35-59: Add focused unit coverage to the
relaunchManagedSupervisorSession suite for the successful spawnSync path,
asserting it returns true when the output contains
NEMOCLAW_SUPERVISOR_RELAUNCHED. Also add a direct test for
NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH=1 confirming the action returns false
without invoking spawnSync, while retaining the existing failure-path tests.
🪄 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: 38b39e8a-09d9-446c-9ff3-4e716a8f57a3

📥 Commits

Reviewing files that changed from the base of the PR and between ecaec7e and c68de8e.

📒 Files selected for processing (3)
  • src/lib/actions/sandbox/supervisor-relaunch.test.ts
  • src/lib/actions/sandbox/supervisor-relaunch.ts
  • test/process-recovery-supervisor-relaunch.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/actions/sandbox/supervisor-relaunch.ts

Comment thread test/process-recovery-supervisor-relaunch.test.ts Outdated
Comment thread test/process-recovery-supervisor-relaunch.test.ts Outdated
@cv

cv commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Addressed the provenance blocker in f18bd981b by removing the sandbox-exec background launch. The root controller now authorizes recovery only with a dedicated stable no-supervisor result derived from two complete scans with unchanged PID 1. The host re-confirms that state against the pinned old container, transactionally recreates the legacy keepalive container with a credential-free managed startup command from the immutable image identity, and probes the replacement through managed control pinned to its container ID. The previous container is removed only after managed health and settle checks pass; failure triggers rollback and rebuild or re-onboard guidance. The docs now describe this trust boundary and writable-layer limitation.

Verification on this revision:

  • Full CLI: 789 files, 8,397 tests passed; 1 skipped.
  • Focused container/recovery unit matrix: 17 files, 187 tests passed.
  • Focused managed-controller/recovery integration: 2 files, 8 tests passed; an additional 122-test recovery/controller matrix passed during review.
  • npm run check:diff and normal pre-push hooks passed.
  • npm run docs passed with 0 errors.
  • Maintainer code/security review found no remaining code blocker. Live E2E and PR CI are in progress and remain required before merge.

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

🧹 Nitpick comments (1)
src/lib/onboard/docker-startup-command-patch.test.ts (1)

239-244: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make the rollback proof target the original container.

This mock returns the same inspect fixture for every inspect command, regardless of the requested container ID. The test would therefore pass even if production inspected the backup or another container instead of old-container-id. Dispatch on the requested ID so the test validates the rollback boundary.

Suggested test adjustment
-              : args[0] === "inspect"
+              : args[0] === "inspect" && args[args.length - 1] === "old-container-id"
                 ? JSON.stringify([inspectFixture()])
                 : "",
🤖 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/onboard/docker-startup-command-patch.test.ts` around lines 239 - 244,
Update the dockerCapture mock in the relevant test to inspect args[1] and return
inspectFixture() only when the requested container ID is old-container-id;
return an empty or appropriate non-matching result for other IDs. Keep the
existing ps behavior unchanged so the rollback assertion specifically proves
production targets the original container.

Source: Path instructions

🤖 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 `@docs/reference/commands.mdx`:
- Line 3141: Reformat the documentation text near the sandbox remote-binding
instructions so each of its three sentences occupies a separate source line,
preserving the wording and Markdown/MDX formatting.

In `@src/lib/onboard/docker-gpu-patch.ts`:
- Around line 1090-1093: Update the error message in the container
identity-mismatch path to state that the operation is pinned but the observed
Docker container identity differs from the expected identity. Remove the
misleading “unpinned startup-command recreation” wording while preserving the
existing sandbox name context and throw behavior.

In `@src/lib/sandbox/privileged-exec.ts`:
- Around line 223-228: Update the identity check in the privileged execution
path to treat only undefined expectedContainerId as omitted, while rejecting an
empty expectedContainerId instead of bypassing validation. Preserve the existing
mismatch error for non-empty IDs and ensure malformed or missing upstream
identities fail closed.

---

Nitpick comments:
In `@src/lib/onboard/docker-startup-command-patch.test.ts`:
- Around line 239-244: Update the dockerCapture mock in the relevant test to
inspect args[1] and return inspectFixture() only when the requested container ID
is old-container-id; return an empty or appropriate non-matching result for
other IDs. Keep the existing ps behavior unchanged so the rollback assertion
specifically proves production targets the original container.
🪄 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: f755b071-d8ef-4f4f-bae8-5d38e6ff8306

📥 Commits

Reviewing files that changed from the base of the PR and between 9cabecd and f18bd98.

📒 Files selected for processing (26)
  • docs/manage-sandboxes/lifecycle.mdx
  • docs/reference/commands.mdx
  • docs/reference/troubleshooting.mdx
  • scripts/managed-gateway-control.py
  • src/lib/actions/sandbox/gateway-restart.test.ts
  • src/lib/actions/sandbox/gateway-restart.ts
  • src/lib/actions/sandbox/process-recovery.ts
  • src/lib/actions/sandbox/supervisor-relaunch.test.ts
  • src/lib/actions/sandbox/supervisor-relaunch.ts
  • src/lib/onboard/docker-gpu-diagnostic-redaction.test.ts
  • src/lib/onboard/docker-gpu-patch-finalize.test.ts
  • src/lib/onboard/docker-gpu-patch-finalize.ts
  • src/lib/onboard/docker-gpu-patch-validation.test.ts
  • src/lib/onboard/docker-gpu-patch.test.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/onboard/docker-gpu-pre-rollback-diagnostics.test.ts
  • src/lib/onboard/docker-gpu-supervisor-reconnect.ts
  • src/lib/onboard/docker-startup-command-patch.test.ts
  • src/lib/onboard/docker-startup-command-patch.ts
  • src/lib/onboard/docker-startup-command-sandbox-create.test.ts
  • src/lib/onboard/sandbox-create-launch.ts
  • src/lib/sandbox/privileged-exec.test.ts
  • src/lib/sandbox/privileged-exec.ts
  • test/e2e/live/gateway-guard-recovery.test.ts
  • test/managed-gateway-control.test.ts
  • test/process-recovery-supervisor-relaunch.test.ts
✅ Files skipped from review due to trivial changes (2)
  • src/lib/onboard/docker-startup-command-sandbox-create.test.ts
  • docs/manage-sandboxes/lifecycle.mdx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/actions/sandbox/gateway-restart.ts
  • src/lib/onboard/sandbox-create-launch.ts

@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

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/lib/onboard/docker-startup-command-patch.test.ts (1)

239-244: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make the rollback proof target the original container.

This mock returns the same inspect fixture for every inspect command, regardless of the requested container ID. The test would therefore pass even if production inspected the backup or another container instead of old-container-id. Dispatch on the requested ID so the test validates the rollback boundary.

Suggested test adjustment
-              : args[0] === "inspect"
+              : args[0] === "inspect" && args[args.length - 1] === "old-container-id"
                 ? JSON.stringify([inspectFixture()])
                 : "",
🤖 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/onboard/docker-startup-command-patch.test.ts` around lines 239 - 244,
Update the dockerCapture mock in the relevant test to inspect args[1] and return
inspectFixture() only when the requested container ID is old-container-id;
return an empty or appropriate non-matching result for other IDs. Keep the
existing ps behavior unchanged so the rollback assertion specifically proves
production targets the original container.

Source: Path instructions

🤖 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 `@docs/reference/commands.mdx`:
- Line 3141: Reformat the documentation text near the sandbox remote-binding
instructions so each of its three sentences occupies a separate source line,
preserving the wording and Markdown/MDX formatting.

In `@src/lib/onboard/docker-gpu-patch.ts`:
- Around line 1090-1093: Update the error message in the container
identity-mismatch path to state that the operation is pinned but the observed
Docker container identity differs from the expected identity. Remove the
misleading “unpinned startup-command recreation” wording while preserving the
existing sandbox name context and throw behavior.

In `@src/lib/sandbox/privileged-exec.ts`:
- Around line 223-228: Update the identity check in the privileged execution
path to treat only undefined expectedContainerId as omitted, while rejecting an
empty expectedContainerId instead of bypassing validation. Preserve the existing
mismatch error for non-empty IDs and ensure malformed or missing upstream
identities fail closed.

---

Nitpick comments:
In `@src/lib/onboard/docker-startup-command-patch.test.ts`:
- Around line 239-244: Update the dockerCapture mock in the relevant test to
inspect args[1] and return inspectFixture() only when the requested container ID
is old-container-id; return an empty or appropriate non-matching result for
other IDs. Keep the existing ps behavior unchanged so the rollback assertion
specifically proves production targets the original container.
🪄 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: f755b071-d8ef-4f4f-bae8-5d38e6ff8306

📥 Commits

Reviewing files that changed from the base of the PR and between 9cabecd and f18bd98.

📒 Files selected for processing (26)
  • docs/manage-sandboxes/lifecycle.mdx
  • docs/reference/commands.mdx
  • docs/reference/troubleshooting.mdx
  • scripts/managed-gateway-control.py
  • src/lib/actions/sandbox/gateway-restart.test.ts
  • src/lib/actions/sandbox/gateway-restart.ts
  • src/lib/actions/sandbox/process-recovery.ts
  • src/lib/actions/sandbox/supervisor-relaunch.test.ts
  • src/lib/actions/sandbox/supervisor-relaunch.ts
  • src/lib/onboard/docker-gpu-diagnostic-redaction.test.ts
  • src/lib/onboard/docker-gpu-patch-finalize.test.ts
  • src/lib/onboard/docker-gpu-patch-finalize.ts
  • src/lib/onboard/docker-gpu-patch-validation.test.ts
  • src/lib/onboard/docker-gpu-patch.test.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/onboard/docker-gpu-pre-rollback-diagnostics.test.ts
  • src/lib/onboard/docker-gpu-supervisor-reconnect.ts
  • src/lib/onboard/docker-startup-command-patch.test.ts
  • src/lib/onboard/docker-startup-command-patch.ts
  • src/lib/onboard/docker-startup-command-sandbox-create.test.ts
  • src/lib/onboard/sandbox-create-launch.ts
  • src/lib/sandbox/privileged-exec.test.ts
  • src/lib/sandbox/privileged-exec.ts
  • test/e2e/live/gateway-guard-recovery.test.ts
  • test/managed-gateway-control.test.ts
  • test/process-recovery-supervisor-relaunch.test.ts
✅ Files skipped from review due to trivial changes (2)
  • src/lib/onboard/docker-startup-command-sandbox-create.test.ts
  • docs/manage-sandboxes/lifecycle.mdx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/actions/sandbox/gateway-restart.ts
  • src/lib/onboard/sandbox-create-launch.ts
🛑 Comments failed to post (3)
docs/reference/commands.mdx (1)

3141-3141: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Split multi-sentence line into one sentence per line.

Line 3141 contains three sentences on a single line.

✏️ Proposed fix
-Set `NEMOCLAW_DASHBOARD_BIND=0.0.0.0` before `$$nemoclaw onboard` to prepare the sandbox for remote exposure and bind the forward on all interfaces. Use the same setting for later `$$nemoclaw <sandbox> connect` calls. A sandbox created without this opt-in must be recreated with `NEMOCLAW_DASHBOARD_BIND=0.0.0.0 $$nemoclaw onboard --recreate-sandbox` before a remote-bind connect is allowed.
+Set `NEMOCLAW_DASHBOARD_BIND=0.0.0.0` before `$$nemoclaw onboard` to prepare the sandbox for remote exposure and bind the forward on all interfaces.
+Use the same setting for later `$$nemoclaw <sandbox> connect` calls.
+A sandbox created without this opt-in must be recreated with `NEMOCLAW_DASHBOARD_BIND=0.0.0.0 $$nemoclaw onboard --recreate-sandbox` before a remote-bind connect is allowed.

As per coding guidelines: "Keep one sentence per line in Markdown and MDX source files."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Set `NEMOCLAW_DASHBOARD_BIND=0.0.0.0` before `$$nemoclaw onboard` to prepare the sandbox for remote exposure and bind the forward on all interfaces.
Use the same setting for later `$$nemoclaw <sandbox> connect` calls.
A sandbox created without this opt-in must be recreated with `NEMOCLAW_DASHBOARD_BIND=0.0.0.0 $$nemoclaw onboard --recreate-sandbox` before a remote-bind connect is allowed.
🤖 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 `@docs/reference/commands.mdx` at line 3141, Reformat the documentation text
near the sandbox remote-binding instructions so each of its three sentences
occupies a separate source line, preserving the wording and Markdown/MDX
formatting.

Source: Coding guidelines

src/lib/onboard/docker-gpu-patch.ts (1)

1090-1093: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clarify the identity-mismatch diagnostic.

The operation is pinned; it is being rejected because the observed container identity differs from the expected one. “Refusing an unpinned startup-command recreation” is misleading and can send recovery troubleshooting in the wrong direction.

Suggested wording
-          "refusing an unpinned startup-command recreation.",
+          "refusing startup-command recreation because the container identity changed.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      throw new Error(
        `OpenShell Docker container identity changed for sandbox '${options.sandboxName}'; ` +
          "refusing startup-command recreation because the container identity changed.",
      );
🤖 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/onboard/docker-gpu-patch.ts` around lines 1090 - 1093, Update the
error message in the container identity-mismatch path to state that the
operation is pinned but the observed Docker container identity differs from the
expected identity. Remove the misleading “unpinned startup-command recreation”
wording while preserving the existing sandbox name context and throw behavior.
src/lib/sandbox/privileged-exec.ts (1)

223-228: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Make the identity pin fail closed for empty IDs.

expectedContainerId && treats "" as “not supplied,” so a malformed or missing upstream identity can silently disable the container check at this privileged boundary. Treat only undefined as omitted and reject an empty expected ID.

Proposed fix
-    if (expectedContainerId && container !== expectedContainerId) {
+    if (expectedContainerId !== undefined && container !== expectedContainerId) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    if (expectedContainerId !== undefined && container !== expectedContainerId) {
      throw new Error(
        `OpenShell container identity changed for sandbox '${sandboxName}'; ` +
          "refusing privileged execution against a different container.",
      );
    }
🤖 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/sandbox/privileged-exec.ts` around lines 223 - 228, Update the
identity check in the privileged execution path to treat only undefined
expectedContainerId as omitted, while rejecting an empty expectedContainerId
instead of bypassing validation. Preserve the existing mismatch error for
non-empty IDs and ensure malformed or missing upstream identities fail closed.

Source: Path instructions

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv

cv commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

@coderabbitai review

Addressed all findings from review 4679197751 in 569b7ac5b:

  • Explicit empty container pins now fail closed in both privileged execution and startup-command recreation, with regression tests.
  • The identity-mismatch diagnostic now says the observed container differs from the pinned identity.
  • The uncertain-rename rollback test proves its third Docker call re-inspects old-container-id.
  • The dashboard-bind paragraph is split into one sentence per source line.

The focused 95-test matrix, CLI type-check, docs build, test-conditional scan, diff-scoped gate, and normal pre-push checks pass on this revision.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

@cv Thanks for the detailed update. I'll review the changes in commit 569b7ac now, focusing on the fail-closed behavior for empty container pins, the updated identity-mismatch diagnostic message, the rollback test's re-inspection assertion, and the docs formatting split.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🤖 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 `@docs/reference/commands.mdx`:
- Line 3121: Update the NEMOCLAW_DASHBOARD_BIND documentation to explicitly
scope the 0.0.0.0 remote-bind opt-in to non-WSL or other SSH-deployed hosts,
while preserving the stated WSL all-interface behavior when unset. Use direct,
active wording consistently across the referenced dashboard-binding
documentation entries.
- Around line 1036-1038: Update the missing-supervisor recovery description near
the managed controller flow to state that the two zero-supervisor scans are
unchanged and root-controller-attested, in addition to requiring a stable PID 1.
Keep the existing transactional recreation, credential-free startup, identity
pinning, rollback retention, health, settle-check, and writable-layer caveats
unchanged.
🪄 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: 6a5f2cec-9c27-4d71-b67a-f2095f895834

📥 Commits

Reviewing files that changed from the base of the PR and between 9cabecd and 569b7ac.

📒 Files selected for processing (27)
  • docs/manage-sandboxes/lifecycle.mdx
  • docs/reference/commands.mdx
  • docs/reference/troubleshooting.mdx
  • scripts/managed-gateway-control.py
  • src/lib/actions/sandbox/gateway-restart.test.ts
  • src/lib/actions/sandbox/gateway-restart.ts
  • src/lib/actions/sandbox/process-recovery.ts
  • src/lib/actions/sandbox/supervisor-relaunch.test.ts
  • src/lib/actions/sandbox/supervisor-relaunch.ts
  • src/lib/onboard/docker-gpu-diagnostic-redaction.test.ts
  • src/lib/onboard/docker-gpu-patch-finalize.test.ts
  • src/lib/onboard/docker-gpu-patch-finalize.ts
  • src/lib/onboard/docker-gpu-patch-validation.test.ts
  • src/lib/onboard/docker-gpu-patch.test.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/onboard/docker-gpu-pre-rollback-diagnostics.test.ts
  • src/lib/onboard/docker-gpu-supervisor-reconnect.ts
  • src/lib/onboard/docker-startup-command-patch.test.ts
  • src/lib/onboard/docker-startup-command-patch.ts
  • src/lib/onboard/docker-startup-command-sandbox-create.test.ts
  • src/lib/onboard/sandbox-create-launch.ts
  • src/lib/sandbox/privileged-exec.test.ts
  • src/lib/sandbox/privileged-exec.ts
  • test/e2e/live/gateway-guard-recovery.test.ts
  • test/e2e/mock-parity.json
  • test/managed-gateway-control.test.ts
  • test/process-recovery-supervisor-relaunch.test.ts
✅ Files skipped from review due to trivial changes (2)
  • src/lib/onboard/docker-gpu-patch-validation.test.ts
  • docs/manage-sandboxes/lifecycle.mdx
🚧 Files skipped from review as they are similar to previous changes (22)
  • src/lib/onboard/docker-gpu-supervisor-reconnect.ts
  • src/lib/sandbox/privileged-exec.test.ts
  • src/lib/onboard/docker-gpu-diagnostic-redaction.test.ts
  • src/lib/onboard/docker-gpu-patch-finalize.ts
  • src/lib/actions/sandbox/gateway-restart.ts
  • src/lib/actions/sandbox/supervisor-relaunch.test.ts
  • src/lib/onboard/docker-startup-command-sandbox-create.test.ts
  • src/lib/onboard/docker-startup-command-patch.ts
  • docs/reference/troubleshooting.mdx
  • src/lib/onboard/docker-gpu-pre-rollback-diagnostics.test.ts
  • src/lib/sandbox/privileged-exec.ts
  • src/lib/onboard/docker-gpu-patch-finalize.test.ts
  • src/lib/onboard/sandbox-create-launch.ts
  • src/lib/onboard/docker-gpu-patch.test.ts
  • test/process-recovery-supervisor-relaunch.test.ts
  • src/lib/actions/sandbox/gateway-restart.test.ts
  • src/lib/onboard/docker-startup-command-patch.test.ts
  • scripts/managed-gateway-control.py
  • src/lib/actions/sandbox/supervisor-relaunch.ts
  • test/managed-gateway-control.test.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/actions/sandbox/process-recovery.ts

@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

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

🤖 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 `@docs/reference/commands.mdx`:
- Line 3121: Update the NEMOCLAW_DASHBOARD_BIND documentation to explicitly
scope the 0.0.0.0 remote-bind opt-in to non-WSL or other SSH-deployed hosts,
while preserving the stated WSL all-interface behavior when unset. Use direct,
active wording consistently across the referenced dashboard-binding
documentation entries.
- Around line 1036-1038: Update the missing-supervisor recovery description near
the managed controller flow to state that the two zero-supervisor scans are
unchanged and root-controller-attested, in addition to requiring a stable PID 1.
Keep the existing transactional recreation, credential-free startup, identity
pinning, rollback retention, health, settle-check, and writable-layer caveats
unchanged.
🪄 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: 6a5f2cec-9c27-4d71-b67a-f2095f895834

📥 Commits

Reviewing files that changed from the base of the PR and between 9cabecd and 569b7ac.

📒 Files selected for processing (27)
  • docs/manage-sandboxes/lifecycle.mdx
  • docs/reference/commands.mdx
  • docs/reference/troubleshooting.mdx
  • scripts/managed-gateway-control.py
  • src/lib/actions/sandbox/gateway-restart.test.ts
  • src/lib/actions/sandbox/gateway-restart.ts
  • src/lib/actions/sandbox/process-recovery.ts
  • src/lib/actions/sandbox/supervisor-relaunch.test.ts
  • src/lib/actions/sandbox/supervisor-relaunch.ts
  • src/lib/onboard/docker-gpu-diagnostic-redaction.test.ts
  • src/lib/onboard/docker-gpu-patch-finalize.test.ts
  • src/lib/onboard/docker-gpu-patch-finalize.ts
  • src/lib/onboard/docker-gpu-patch-validation.test.ts
  • src/lib/onboard/docker-gpu-patch.test.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/onboard/docker-gpu-pre-rollback-diagnostics.test.ts
  • src/lib/onboard/docker-gpu-supervisor-reconnect.ts
  • src/lib/onboard/docker-startup-command-patch.test.ts
  • src/lib/onboard/docker-startup-command-patch.ts
  • src/lib/onboard/docker-startup-command-sandbox-create.test.ts
  • src/lib/onboard/sandbox-create-launch.ts
  • src/lib/sandbox/privileged-exec.test.ts
  • src/lib/sandbox/privileged-exec.ts
  • test/e2e/live/gateway-guard-recovery.test.ts
  • test/e2e/mock-parity.json
  • test/managed-gateway-control.test.ts
  • test/process-recovery-supervisor-relaunch.test.ts
✅ Files skipped from review due to trivial changes (2)
  • src/lib/onboard/docker-gpu-patch-validation.test.ts
  • docs/manage-sandboxes/lifecycle.mdx
🚧 Files skipped from review as they are similar to previous changes (22)
  • src/lib/onboard/docker-gpu-supervisor-reconnect.ts
  • src/lib/sandbox/privileged-exec.test.ts
  • src/lib/onboard/docker-gpu-diagnostic-redaction.test.ts
  • src/lib/onboard/docker-gpu-patch-finalize.ts
  • src/lib/actions/sandbox/gateway-restart.ts
  • src/lib/actions/sandbox/supervisor-relaunch.test.ts
  • src/lib/onboard/docker-startup-command-sandbox-create.test.ts
  • src/lib/onboard/docker-startup-command-patch.ts
  • docs/reference/troubleshooting.mdx
  • src/lib/onboard/docker-gpu-pre-rollback-diagnostics.test.ts
  • src/lib/sandbox/privileged-exec.ts
  • src/lib/onboard/docker-gpu-patch-finalize.test.ts
  • src/lib/onboard/sandbox-create-launch.ts
  • src/lib/onboard/docker-gpu-patch.test.ts
  • test/process-recovery-supervisor-relaunch.test.ts
  • src/lib/actions/sandbox/gateway-restart.test.ts
  • src/lib/onboard/docker-startup-command-patch.test.ts
  • scripts/managed-gateway-control.py
  • src/lib/actions/sandbox/supervisor-relaunch.ts
  • test/managed-gateway-control.test.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/actions/sandbox/process-recovery.ts
🛑 Comments failed to post (2)
docs/reference/commands.mdx (2)

1036-1038: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Document the complete missing-supervisor proof.

This wording omits that the two scans must be unchanged and root-controller-attested, making the documented recovery gate appear broader than the PR’s safety contract.

Suggested wording
-When the managed controller reports `SUPERVISOR_NOT_RUNNING` after two zero-supervisor process scans with a stable PID 1, a local Docker-driver sandbox with the legacy keepalive startup can enter a transactional container recreation.
+When the managed controller reports `SUPERVISOR_NOT_RUNNING` after two unchanged, root-controller-attested scans confirm no supervisor while PID 1 remains stable, a local Docker-driver sandbox with the legacy keepalive startup can enter a transactional container recreation.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

When the managed controller reports `SUPERVISOR_NOT_RUNNING` after two unchanged, root-controller-attested scans confirm no supervisor while PID 1 remains stable, a local Docker-driver sandbox with the legacy keepalive startup can enter a transactional container recreation.
The recreation uses a credential-free managed startup command, pins the registered container identity, retains the previous container for rollback, and commits only after managed gateway health and the settle check pass.
The recreation preserves mounted sandbox state, but a committed swap does not retain changes stored only in the previous container's writable layer.
🤖 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 `@docs/reference/commands.mdx` around lines 1036 - 1038, Update the
missing-supervisor recovery description near the managed controller flow to
state that the two zero-supervisor scans are unchanged and
root-controller-attested, in addition to requiring a stable PID 1. Keep the
existing transactional recreation, credential-free startup, identity pinning,
rollback retention, health, settle-check, and writable-layer caveats unchanged.

3121-3121: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Clarify the WSL exception for dashboard binding.

The documentation says WSL binds all interfaces when unset, then says only 0.0.0.0 enables remote binding. Scope the latter to the explicit non-WSL opt-in so users do not misinterpret the exposure behavior. The rewrite also follows the required direct, active documentation style.

Suggested wording
-Set `NEMOCLAW_DASHBOARD_BIND=0.0.0.0` before `$$nemoclaw onboard` to prepare the sandbox for remote exposure and bind the forward on all interfaces.
+On non-WSL hosts, set `NEMOCLAW_DASHBOARD_BIND=0.0.0.0` before `$$nemoclaw onboard` to opt into remote exposure and bind the forward on all interfaces.
 Use the same setting for later `$$nemoclaw <sandbox> connect` calls.
-A sandbox created without this opt-in must be recreated with `NEMOCLAW_DASHBOARD_BIND=0.0.0.0 $$nemoclaw onboard --recreate-sandbox` before a remote-bind connect is allowed.
-Only `0.0.0.0` enables the remote bind; onboarding rejects any other non-empty value.
+If you created a sandbox without this opt-in, recreate it with `NEMOCLAW_DASHBOARD_BIND=0.0.0.0 $$nemoclaw onboard --recreate-sandbox` before you use a remote-bind connect.
+Outside WSL, only `0.0.0.0` enables the explicit remote bind; onboarding rejects any other non-empty value.

Also applies to: 3139-3144

🤖 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 `@docs/reference/commands.mdx` at line 3121, Update the NEMOCLAW_DASHBOARD_BIND
documentation to explicitly scope the 0.0.0.0 remote-bind opt-in to non-WSL or
other SSH-deployed hosts, while preserving the stated WSL all-interface behavior
when unset. Use direct, active wording consistently across the referenced
dashboard-binding documentation entries.

Source: Coding guidelines

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv

cv commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

@coderabbitai review

Addressed the final review-body findings in b79b92726:

  • Recovery docs now identify the root-owned controller as the attester of both unchanged zero-supervisor scans.
  • Dashboard remote-bind opt-in is explicitly scoped to non-WSL SSH deployments.
  • Troubleshooting now documents NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH=1 and its no-mutation fallback behavior.
  • Full-flow integration now proves the kill switch prevents container discovery, pinned probing, and recreation while returning rebuild guidance.

Targeted integration, CLI type-check, docs, condition-budget scanning, npm run check:diff, and normal pre-push checks pass on this revision.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

@cv Thanks for the update. I'll review the changes in commit b79b927 now, focusing on the attester documentation for the root-owned controller, the WSL SSH scoping for dashboard remote-bind, the NEMOCLAW_DISABLE_SUPERVISOR_RELAUNCH=1 documentation, and the full-flow integration test proving kill-switch behavior.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@test/process-recovery-supervisor-relaunch.test.ts`:
- Around line 98-104: Update the test around
relaunchManagedSupervisorSessionImpl to assert that the mock was invoked before
checking that no mutation occurred. Keep the existing no-side-effect assertions,
ensuring the test fails when the relaunch branch is skipped for any unrelated
reason.
🪄 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: ea6fac52-ebfc-4e0f-aef4-dde54327275c

📥 Commits

Reviewing files that changed from the base of the PR and between 569b7ac and b79b927.

📒 Files selected for processing (3)
  • docs/reference/commands.mdx
  • docs/reference/troubleshooting.mdx
  • test/process-recovery-supervisor-relaunch.test.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/reference/troubleshooting.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/reference/commands.mdx

Comment thread test/process-recovery-supervisor-relaunch.test.ts
@cv

cv commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Reviewed the remaining CodeRabbit item from review 4679266923; no code change is needed. The full-flow kill-switch test already asserts relaunchManagedSupervisorSessionImpl with toHaveBeenCalledWith("legacy-box", expect.objectContaining({ quiet: false })) before the three no-side-effect assertions. That matcher fails if the relaunch branch is skipped and also verifies the call arguments, so it provides the requested branch-execution proof.

@github-actions

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some tests failed

Run: 29177181325
Workflow ref: fix/6635-gateway-recovery-after-restart
Requested targets: (default — all supported)
Requested test IDs: gpu-e2e
Summary: 0 passed, 1 failed, 0 cancelled, 0 skipped, 0 unknown

Test Result
gpu-e2e ❌ failure

Failed tests: gpu-e2e. Check run artifacts for logs.

@github-actions

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some tests failed

Run: 29177072715
Workflow ref: fix/6635-gateway-recovery-after-restart
Requested targets: (default — all supported)
Requested test IDs: cloud-onboard,gateway-guard-recovery,gpu-e2e,sandbox-operations,credential-sanitization,rebuild-openclaw
Summary: 4 passed, 2 failed, 0 cancelled, 0 skipped, 0 unknown

Test Result
cloud-onboard ✅ success
credential-sanitization ✅ success
gateway-guard-recovery ❌ failure
gpu-e2e ❌ failure
rebuild-openclaw ✅ success
sandbox-operations ✅ success

Failed tests: gateway-guard-recovery, gpu-e2e. Check run artifacts for logs.

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@github-actions

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some tests failed

Run: 29177741579
Workflow ref: fix/6635-gateway-recovery-after-restart
Requested targets: (default — all supported)
Requested test IDs: cloud-onboard,gateway-guard-recovery,gpu-e2e,sandbox-operations,credential-sanitization,rebuild-openclaw
Summary: 5 passed, 1 failed, 0 cancelled, 0 skipped, 0 unknown

Test Result
cloud-onboard ✅ success
credential-sanitization ✅ success
gateway-guard-recovery ❌ failure
gpu-e2e ✅ success
rebuild-openclaw ✅ success
sandbox-operations ✅ success

Failed tests: gateway-guard-recovery. Check run artifacts for logs.

cv added 2 commits July 11, 2026 20:22
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@github-actions

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some tests failed

Run: 29178149876
Workflow ref: fix/6635-gateway-recovery-after-restart
Requested targets: (default — all supported)
Requested test IDs: cloud-onboard,gateway-guard-recovery,gpu-e2e,sandbox-operations,credential-sanitization,rebuild-openclaw
Summary: 5 passed, 1 failed, 0 cancelled, 0 skipped, 0 unknown

Test Result
cloud-onboard ✅ success
credential-sanitization ✅ success
gateway-guard-recovery ❌ failure
gpu-e2e ✅ success
rebuild-openclaw ✅ success
sandbox-operations ✅ success

Failed tests: gateway-guard-recovery. Check run artifacts for logs.

@github-actions

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All requested tests passed

Run: 29178405818
Workflow ref: fix/6635-gateway-recovery-after-restart
Requested targets: (default — all supported)
Requested test IDs: gateway-guard-recovery
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped, 0 unknown

Test Result
gateway-guard-recovery ✅ success

@cv
cv merged commit 5638148 into main Jul 12, 2026
132 of 133 checks passed
@cv
cv deleted the fix/6635-gateway-recovery-after-restart branch July 12, 2026 06:49
@cv cv mentioned this pull request Jul 12, 2026
21 tasks
cv added a commit that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Release-prep documentation for v0.0.81 now summarizes user-facing
changes merged since v0.0.80.
It also closes the Hermes dashboard-profile backup gap and distinguishes
direct blueprint-runner actions from public host CLI commands.

## Changes

- Add the `v0.0.81` section to `docs/about/release-notes.mdx` with links
to the detailed user guides.
- Document that Hermes rebuilds preserve `.hermes/dashboard-home/`,
including Dashboard `MEMORY.md` and `USER.md`.
- Update Hermes manual backup and restore examples to transfer those two
profile files without copying generated configuration or the
secret-bearing dashboard `.env`.
- Explain the new per-item backup failure causes.
- Clarify that migration snapshot retention fragments are direct-runner
arguments and are not exposed by the host `nemoclaw` CLI.

### Source summary

- #6445 -> `docs/about/release-notes.mdx`,
`docs/manage-sandboxes/backup-restore.mdx`, and
`docs/manage-sandboxes/workspace-files.mdx`: Summarize manifest-owned
key-level restore and current-config authority.
- #6617 -> `docs/about/release-notes.mdx` and
`docs/manage-sandboxes/backup-restore.mdx`: Record the fail-closed
`/proc` fallback used to verify an idle Deep Agents runtime before
snapshot creation.
- #6685 -> `docs/about/release-notes.mdx`,
`docs/manage-sandboxes/backup-restore.mdx`, and
`docs/manage-sandboxes/workspace-files.mdx`: Document Hermes Web
Dashboard profile persistence and safe manual transfer.
- #6649 -> `docs/about/release-notes.mdx`: Summarize host-validated
loopback compatible-endpoint routing through the sandbox gateway.
- #6643 -> `docs/about/release-notes.mdx`: Summarize automatic
`max_completion_tokens` handling for GPT-5 and o-series models.
- #6661 -> `docs/about/release-notes.mdx`: Summarize bounded connection
reuse for eligible provider-validation probes.
- #6704 -> `docs/about/release-notes.mdx`: Record that direct blueprint
apply stops instead of persisting incomplete state after provider or
inference setup fails.
- #6677 -> `docs/about/release-notes.mdx`: Summarize transactional
recovery for legacy Docker containers whose managed supervisor
disappeared after restart.
- #6625 -> `docs/about/release-notes.mdx`: Record Hermes managed-startup
persistence across direct Docker restarts.
- #6597 -> `docs/about/release-notes.mdx`: Record final-sandbox gateway
cleanup on macOS.
- #6680 -> `docs/about/release-notes.mdx`: Summarize managed Deep Agents
first-run and process-tree cleanup improvements.
- #6647 -> `docs/about/release-notes.mdx`: Record fail-closed validation
for the managed Deep Agents fetch CA bundle.
- #6645 -> `docs/about/release-notes.mdx`: Summarize WhatsApp loopback
pairing and trusted npm plugin provenance.
- #6673 -> `docs/about/release-notes.mdx` and
`docs/manage-sandboxes/backup-restore.mdx`: Document stopped-sandbox
backup remediation.
- #6631 -> `docs/about/release-notes.mdx` and
`docs/manage-sandboxes/backup-restore.mdx`: Document per-item backup
failure causes.
- #6620 -> `docs/about/release-notes.mdx`: Record the
created-but-not-ready sandbox lifecycle receipt.
- #6664 -> `docs/about/release-notes.mdx`: Record prompt-aware
onboarding progress output.
- #6598 -> `docs/about/release-notes.mdx`: Summarize stale replay-result
invalidation during resumed onboarding.
- #6593 -> `docs/about/release-notes.mdx`: Summarize contextual OpenClaw
audit findings for managed dashboard compatibility settings.
- #6650 -> `docs/about/release-notes.mdx`: Record redaction of
token-shaped URL query values.
- #6638 -> `docs/about/release-notes.mdx`: Record the exact-path MCP
`DELETE` policy recipe for session termination.
- #5453 -> `docs/reference/host-files-and-state.mdx`: Clarify that
snapshot retention actions belong to direct runner integrations and are
not standalone host CLI commands.

### Skipped from docs-skip

- #6633 matched the `openclaw-sandbox-permissive.yaml` path in
`docs/.docs-skip` and produced no documentation in this update.

## Type of Change

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

## Quality Gates

- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: This is a documentation-only
release-prep update; behavior is protected by the merged source PRs, and
the documentation build validates the changed examples and routes.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification

- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — tests are not applicable for this
documentation-only change; `npm run docs` completed successfully.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result: not run for this
documentation-only change.
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only) — 0
errors; two existing Fern warnings remain.
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)
— no new pages.

---
Signed-off-by: Carlos Villela <cvillela@nvidia.com>


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

## Summary by CodeRabbit

- **Documentation**
- Added release notes for v0.0.81 covering state preservation, inference
setup, sandbox recovery, session setup, pairing, diagnostics, and
security policy updates.
- Expanded backup and restore guidance to include dashboard profile
files and clarify files that must not be copied.
- Added dashboard profile persistence details to workspace and rebuild
documentation.
- Clarified snapshot retention guidance and the distinction between host
CLI capabilities and direct runner actions.
  - Added more detailed backup failure reporting information.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
…VIDIA#6677)

<!-- markdownlint-disable MD041 -->
## Summary

After a local Docker-driver sandbox container restart, legacy containers
whose persisted startup command was `sleep infinity` lost the
`nemoclaw-start` workload session. `recover` now handles only a
root-controller-attested, stable no-supervisor state by transactionally
recreating the registered container with a credential-free managed
startup command. NemoClaw retains the previous container until the
replacement passes container-pinned managed-control health and settle
checks; otherwise it attempts rollback and returns rebuild or re-onboard
guidance.

## Related Issue

Fixes NVIDIA#6635

## Changes

- Added the dedicated `SUPERVISOR_NOT_RUNNING` controller result. It is
emitted only after two complete zero-supervisor scans with unchanged PID
1 and no unreadable, ambiguous, or changing process state. Those cases
remain `SUPERVISOR_UNAVAILABLE` and cannot authorize container mutation.
- Replaced the ordinary sandbox-exec background launch with a host-side
container transaction. Recovery pins the registered container identity,
verifies the legacy `sleep infinity` startup, uses the immutable image
identity, and persists `env ... nemoclaw-start` as the managed startup
command.
- Reconstructs only non-credential runtime environment values.
Credential placeholders, credential-bearing proxy URLs, and
secret-shaped diagnostics are omitted or redacted.
- Retains the previous container for rollback. The replacement is probed
through root managed control pinned to its container ID; recovery
commits only after managed gateway health and the settle check pass.
- Keeps `SUPERVISOR_NOT_RUNNING` distinct from privileged-control
failures and prints non-circular rebuild or re-onboard guidance when
trusted recovery cannot complete.
- Added unit and integration coverage for stable absence, ambiguity and
race refusal, container identity pinning, immutable-image recreation,
invalid startup-command refusal, credential exclusion, rollback,
commit-after-health, and sanitized diagnostics.
- Extended `gateway-guard-recovery` with a real Docker container
restart. It verifies container replacement, managed supervisor topology,
forwarded health, credential exclusion, and a successful agent inference
request after recovery.
- Updated lifecycle, command-reference, and troubleshooting
documentation for the transactional recovery boundary and writable-layer
limitation.

## Verification Evidence

- Final-head PR CI: [run
29178402069](https://github.com/NVIDIA/NemoClaw/actions/runs/29178402069)
passed all eight CLI shards, type checking, static checks, plugin and
installer tests, E2E support, and the remaining required non-live jobs.
- Focused container/recovery unit matrix: 17 files and 187 tests passed.
- Focused managed-controller/recovery integration matrix: 2 files and 8
tests passed.
- Additional recovery/controller integration matrix: 122 tests passed
during the implementation review.
- E2E support project: 116 files and 946 tests passed; live/fast parity
passed.
- `npm run check:diff`: all applicable pre-commit, commit-message,
secret-scan, repository, and pre-push checks passed.
- Normal pre-push hooks: plugin TypeScript, checked-JavaScript build,
CLI TypeScript, and version synchronization passed.
- `npm run docs`: passed with 0 errors; two pre-existing hidden-page
warnings remain.
- Local broad integration was attempted but is not claimed as a pass:
the shared host has an occupied port required by an unchanged onboarding
test, and the isolated worktree's temporary dependency symlink is
intentionally rejected by an unchanged trusted-path guard. The affected
tests pass when those environmental constraints are removed. PR CI
remains authoritative.
- Final-head live `gateway-guard-recovery`: [run
29178405818](https://github.com/NVIDIA/NemoClaw/actions/runs/29178405818)
passed 1/1. Recovery exited 0 without timing out, proved one managed
supervisor under PID 1, restored forward health with HTTP 200, and
completed live inference with the expected answer.
[Artifact](https://github.com/NVIDIA/NemoClaw/actions/runs/29178405818/artifacts/8255686220).
- Final-head automatic release gate: [run
29178569987](https://github.com/NVIDIA/NemoClaw/actions/runs/29178569987)
passed both `onboard-repair` and `onboard-resume`.
- Adjacent live targets on production commit `a89859bb5` passed:
[gpu-e2e](https://github.com/NVIDIA/NemoClaw/actions/runs/29178149876/job/86611005998),
[credential-sanitization](https://github.com/NVIDIA/NemoClaw/actions/runs/29178149876/job/86611006184),
[rebuild-openclaw](https://github.com/NVIDIA/NemoClaw/actions/runs/29178149876/job/86611006091),
[sandbox-operations](https://github.com/NVIDIA/NemoClaw/actions/runs/29178149876/job/86611006238),
and
[cloud-onboard](https://github.com/NVIDIA/NemoClaw/actions/runs/29178149876/job/86611006233).
Final commit `2c57e7ea2` changes only the live topology test UID
assertion.

## Type of Change

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

## Quality Gates
<!-- Check exactly one tests line and one docs line. Check other lines
when applicable. Add every requested justification or approval
reference. -->
- [x] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [ ] Tests not applicable — justification:
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [x] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [x] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification: maintainer security
review found no remaining code blocker;
[Terra](https://github.com/NVIDIA/NemoClaw/actions/runs/29178402046)
reports `merge_as_is` with zero findings, and the final-head live
recovery proof passed.
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification
<!-- Check each applicable item only when supported by the requested
evidence. Run targeted tests once per relevant change set and rerun
after later edits or hook autofixes that can affect the tested behavior.
Do not rerun hook-covered checks. -->
- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result: focused recovery
matrix 149 passed after the readiness and forward changes; focused
container/recovery 187 passed; focused controller/recovery integration 8
passed; E2E support 946 passed; final-head live gateway recovery 1/1
passed.
- [x] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result: final-head [PR
CI](https://github.com/NVIDIA/NemoClaw/actions/runs/29178402069) and
[E2E / PR
Gate](https://github.com/NVIDIA/NemoClaw/actions/runs/29178559443)
passed; local broad-run limitations remain documented above.
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [x] `npm run docs` builds without new warnings (doc changes only) — 0
errors; two pre-existing hidden-page warnings unchanged.
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

---
Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>


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

* **New Features**
* Added a trusted legacy recovery path for supported local Docker
sandboxes when the managed supervisor isn’t running.
* Added a new lifecycle behavior flag to disable automatic supervisor
relaunch during recovery.
* **Bug Fixes**
* Improved gateway restart failure classification (including a distinct
“supervisor not running” outcome) and corresponding recovery hints.
* Strengthened safeguards to prevent recovery when container identity
changes, and improved Docker rollback/restore behavior when results are
incomplete.
* Added validation to prevent privileged execution when the expected
container identity doesn’t match.
* **Documentation**
* Expanded recovery and troubleshooting guidance for
supervisor-not-running scenarios and the disable-relaunch flag.
* **Tests**
* Added/updated coverage for supervisor relaunch recovery decisions and
Docker redaction/patch edge cases.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Release-prep documentation for v0.0.81 now summarizes user-facing
changes merged since v0.0.80.
It also closes the Hermes dashboard-profile backup gap and distinguishes
direct blueprint-runner actions from public host CLI commands.

## Changes

- Add the `v0.0.81` section to `docs/about/release-notes.mdx` with links
to the detailed user guides.
- Document that Hermes rebuilds preserve `.hermes/dashboard-home/`,
including Dashboard `MEMORY.md` and `USER.md`.
- Update Hermes manual backup and restore examples to transfer those two
profile files without copying generated configuration or the
secret-bearing dashboard `.env`.
- Explain the new per-item backup failure causes.
- Clarify that migration snapshot retention fragments are direct-runner
arguments and are not exposed by the host `nemoclaw` CLI.

### Source summary

- NVIDIA#6445 -> `docs/about/release-notes.mdx`,
`docs/manage-sandboxes/backup-restore.mdx`, and
`docs/manage-sandboxes/workspace-files.mdx`: Summarize manifest-owned
key-level restore and current-config authority.
- NVIDIA#6617 -> `docs/about/release-notes.mdx` and
`docs/manage-sandboxes/backup-restore.mdx`: Record the fail-closed
`/proc` fallback used to verify an idle Deep Agents runtime before
snapshot creation.
- NVIDIA#6685 -> `docs/about/release-notes.mdx`,
`docs/manage-sandboxes/backup-restore.mdx`, and
`docs/manage-sandboxes/workspace-files.mdx`: Document Hermes Web
Dashboard profile persistence and safe manual transfer.
- NVIDIA#6649 -> `docs/about/release-notes.mdx`: Summarize host-validated
loopback compatible-endpoint routing through the sandbox gateway.
- NVIDIA#6643 -> `docs/about/release-notes.mdx`: Summarize automatic
`max_completion_tokens` handling for GPT-5 and o-series models.
- NVIDIA#6661 -> `docs/about/release-notes.mdx`: Summarize bounded connection
reuse for eligible provider-validation probes.
- NVIDIA#6704 -> `docs/about/release-notes.mdx`: Record that direct blueprint
apply stops instead of persisting incomplete state after provider or
inference setup fails.
- NVIDIA#6677 -> `docs/about/release-notes.mdx`: Summarize transactional
recovery for legacy Docker containers whose managed supervisor
disappeared after restart.
- NVIDIA#6625 -> `docs/about/release-notes.mdx`: Record Hermes managed-startup
persistence across direct Docker restarts.
- NVIDIA#6597 -> `docs/about/release-notes.mdx`: Record final-sandbox gateway
cleanup on macOS.
- NVIDIA#6680 -> `docs/about/release-notes.mdx`: Summarize managed Deep Agents
first-run and process-tree cleanup improvements.
- NVIDIA#6647 -> `docs/about/release-notes.mdx`: Record fail-closed validation
for the managed Deep Agents fetch CA bundle.
- NVIDIA#6645 -> `docs/about/release-notes.mdx`: Summarize WhatsApp loopback
pairing and trusted npm plugin provenance.
- NVIDIA#6673 -> `docs/about/release-notes.mdx` and
`docs/manage-sandboxes/backup-restore.mdx`: Document stopped-sandbox
backup remediation.
- NVIDIA#6631 -> `docs/about/release-notes.mdx` and
`docs/manage-sandboxes/backup-restore.mdx`: Document per-item backup
failure causes.
- NVIDIA#6620 -> `docs/about/release-notes.mdx`: Record the
created-but-not-ready sandbox lifecycle receipt.
- NVIDIA#6664 -> `docs/about/release-notes.mdx`: Record prompt-aware
onboarding progress output.
- NVIDIA#6598 -> `docs/about/release-notes.mdx`: Summarize stale replay-result
invalidation during resumed onboarding.
- NVIDIA#6593 -> `docs/about/release-notes.mdx`: Summarize contextual OpenClaw
audit findings for managed dashboard compatibility settings.
- NVIDIA#6650 -> `docs/about/release-notes.mdx`: Record redaction of
token-shaped URL query values.
- NVIDIA#6638 -> `docs/about/release-notes.mdx`: Record the exact-path MCP
`DELETE` policy recipe for session termination.
- NVIDIA#5453 -> `docs/reference/host-files-and-state.mdx`: Clarify that
snapshot retention actions belong to direct runner integrations and are
not standalone host CLI commands.

### Skipped from docs-skip

- NVIDIA#6633 matched the `openclaw-sandbox-permissive.yaml` path in
`docs/.docs-skip` and produced no documentation in this update.

## Type of Change

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

## Quality Gates

- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: This is a documentation-only
release-prep update; behavior is protected by the merged source PRs, and
the documentation build validates the changed examples and routes.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification

- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — tests are not applicable for this
documentation-only change; `npm run docs` completed successfully.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result: not run for this
documentation-only change.
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only) — 0
errors; two existing Fern warnings remain.
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)
— no new pages.

---
Signed-off-by: Carlos Villela <cvillela@nvidia.com>


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

## Summary by CodeRabbit

- **Documentation**
- Added release notes for v0.0.81 covering state preservation, inference
setup, sandbox recovery, session setup, pairing, diagnostics, and
security policy updates.
- Expanded backup and restore guidance to include dashboard profile
files and clarify files that must not be copied.
- Added dashboard profile persistence details to workspace and rebuild
documentation.
- Clarified snapshot retention guidance and the distinction between host
CLI capabilities and direct runner actions.
  - Added more detailed backup failure reporting information.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-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: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery bug-fix PR fixes a bug or regression

Projects

None yet

3 participants