fix(sandbox): align recreate readiness-wait budget with connect (120s) - #7784
Conversation
The post-recreate OpenShell readiness wait gave up after 30s, 4x sooner than `connect`'s `waitForSandboxReadyOrExit` (120s) — even though both prove the same thing: that a just-recreated sandbox has re-registered as Ready. On a cold start the sandbox can sit in a transient `phase: Error` settling window longer than 30s but well within 120s. When that happened, `start`'s recovery abandoned the sandbox and surfaced the manual-recover hint, while `connect --probe-only` (with the larger budget) recovered the exact same sandbox and started the primary dashboard/API forward. That asymmetry is the intermittent start/recovery failure reported in #7227. Introduce a single `GATEWAY_RECOVERY_WAIT_DEFAULT_SECONDS = 120` constant and use it for both readiness-wait default sites (`waitForRecreatedSandboxOpenShellReadyResult` and `waitForRecoveredSandboxGateway`). The `NEMOCLAW_GATEWAY_RECOVERY_WAIT_SECONDS` env override is unchanged. The agent health-probe timeout (30s) and the post-ready settle pause (25s) are distinct concepts and are left untouched. This is a low-probability cold-start race that does not reproduce deterministically, so this is a principled budget alignment rather than an empirically-timed value; keeping #7227 open to confirm over repeated cold starts is reasonable. Refs #7227 Signed-off-by: Yanyun Liao <yanyunl@nvidia.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
📝 WalkthroughWalkthroughRecovery readiness now uses a shared 120-second default instead of 30 seconds for recreated-sandbox OpenShell checks and recovered gateway waits. A test verifies readiness succeeds after eleven transient failures and a successful twelfth probe. ChangesGateway recovery budget
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Code Coverage OverviewLanguages: TypeScript TypeScript / code-coverage/pluginThe overall coverage in commit 7d06310 in the TypeScript / code-coverage/cliThe overall coverage in commit 7d06310 in the Show a code coverage summary of the most impacted files.
Updated |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/lib/actions/sandbox/process-recovery.test.ts (1)
112-147: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winCover the separately changed recovered-gateway default.
This regression test only exercises
waitForRecreatedSandboxOpenShellReady. Add a behavioral test wherewaitForRecoveredSandboxGatewayalso survives the old 30-second/11-attempt budget; its existing immediate-success test would pass with either default.🤖 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.test.ts` around lines 112 - 147, Extend the recovery tests with a behavioral case for waitForRecoveredSandboxGateway that omits timeoutSeconds and the environment override, returns transient failures for at least 11 probes, then succeeds, and verifies the 12th probe is reached and recovery succeeds. Keep the existing immediate-success test unchanged and mirror the default-budget setup used by waitForRecreatedSandboxOpenShellReady.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 `@src/lib/actions/sandbox/process-recovery.test.ts`:
- Line 118: Update the test setup around the
NEMOCLAW_GATEWAY_RECOVERY_WAIT_SECONDS environment variable to save its prior
value, then restore that exact value in a finally block after the test
completes, including when assertions or setup fail. Preserve the existing test
behavior while preventing process.env state from leaking into later tests.
---
Nitpick comments:
In `@src/lib/actions/sandbox/process-recovery.test.ts`:
- Around line 112-147: Extend the recovery tests with a behavioral case for
waitForRecoveredSandboxGateway that omits timeoutSeconds and the environment
override, returns transient failures for at least 11 probes, then succeeds, and
verifies the 12th probe is reached and recovery succeeds. Keep the existing
immediate-success test unchanged and mirror the default-budget setup used by
waitForRecreatedSandboxOpenShellReady.
🪄 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: 472a454e-2d75-4af5-bd40-3b88b9b6d210
📒 Files selected for processing (2)
src/lib/actions/sandbox/process-recovery.test.tssrc/lib/actions/sandbox/process-recovery.ts
| // retrying a cold-start phase:Error settling window that exceeds the old | ||
| // 30s / 11-attempt budget. The 12th probe (past the old 11-attempt cap) must | ||
| // still be reached, so the primary dashboard/API forward is not abandoned. | ||
| delete process.env.NEMOCLAW_GATEWAY_RECOVERY_WAIT_SECONDS; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Restore the previous environment value.
This test mutates process.env directly and never restores the prior value, so later tests can become order-dependent. Save the value and restore it in a finally block.
Proposed fix
+ const previousRecoveryWait = process.env.NEMOCLAW_GATEWAY_RECOVERY_WAIT_SECONDS;
delete process.env.NEMOCLAW_GATEWAY_RECOVERY_WAIT_SECONDS;
+ try {
// existing assertions
+ } finally {
+ if (previousRecoveryWait === undefined) {
+ delete process.env.NEMOCLAW_GATEWAY_RECOVERY_WAIT_SECONDS;
+ } else {
+ process.env.NEMOCLAW_GATEWAY_RECOVERY_WAIT_SECONDS = previousRecoveryWait;
+ }
+ }🤖 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.test.ts` at line 118, Update the
test setup around the NEMOCLAW_GATEWAY_RECOVERY_WAIT_SECONDS environment
variable to save its prior value, then restore that exact value in a finally
block after the test completes, including when assertions or setup fail.
Preserve the existing test behavior while preventing process.env state from
leaking into later tests.
Source: Path instructions
PR Review Advisor — No blocking findings reportedAdvisor assessment: No blocking advisor findings reported Model lanes
Nemotron output stays in workflow artifacts and does not change the assessment above. E2E guidanceAdvisory only. E2E / PR Gate selects and runs jobs independently. Recommended E2E: 1 optional E2E recommendation
This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge. |
|
@yanyunl1991 if you continue working on this, consider a wider refactoring for timeout handling |
<!-- markdownlint-disable MD041 --> ## Summary Add the canonical pre-tag release entry for NemoClaw v0.0.98. The dated entry records the user-visible changes merged after v0.0.97 and links each release theme to its published documentation. ## Changes - Add `docs/changelog/2026-07-29.mdx` with the exact `## v0.0.98` release heading. - Summarize Hermes 0.19, Deep Agents Code automation and skill safety, readiness diagnostics, lifecycle recovery, uninstall behavior, messaging conflicts, dependency hardening, and bounded diagnostics. - Use the parser-safe MDX SPDX comment and root-absolute routes for published OpenClaw, Hermes, and Deep Agents documentation. ### Source summary - [#7849](#7849) -> `docs/changelog/2026-07-29.mdx`: Record the Hermes 0.19 runtime migration repairs for cron state, dashboard seeding, and MCP naming. - [#7662](#7662) -> `docs/changelog/2026-07-29.mdx`: Record bounded gateway and Docker subprocess diagnostics. - [#7850](#7850) -> `docs/changelog/2026-07-29.mdx`: Record verified no-clobber Deep Agents Code skill installation. - [#7848](#7848) -> `docs/changelog/2026-07-29.mdx`: Record post-reboot delivery-chain recovery for visible OpenClaw sandboxes. - [#7831](#7831) -> `docs/changelog/2026-07-29.mdx`: Record OpenShell gateway-state preservation during uninstall. - [#7827](#7827) -> `docs/changelog/2026-07-29.mdx`: Record the removal of upstream test sources from published Hermes images. - [#7775](#7775) -> `docs/changelog/2026-07-29.mdx`: Record the blocking diagnostic for unsupported `DOCKER_HOST` values. - [#7833](#7833) -> `docs/changelog/2026-07-29.mdx`: Record reviewed Python dependency baselines for Hermes and Deep Agents Code images. - [#7771](#7771) -> `docs/changelog/2026-07-29.mdx`: Record the managed Hermes Agent 0.19.0 upgrade. - [#7811](#7811) -> `docs/changelog/2026-07-29.mdx`: Record fail-closed messaging channel conflict handling. - [#7797](#7797) -> `docs/changelog/2026-07-29.mdx`: Record the managed non-interactive Deep Agents Code JSON envelope. - [#7782](#7782) -> `docs/changelog/2026-07-29.mdx`: Record the storage-remediation readiness capability. - [#7784](#7784) -> `docs/changelog/2026-07-29.mdx`: Record the 120-second OpenShell readiness budget for sandbox recreation. - [#7810](#7810) -> `docs/changelog/2026-07-29.mdx`: Record rejection of stale Deep Agents Code security inventories. ## Type of Change - [ ] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [x] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Quality Gates - [ ] Tests added or updated for changed behavior - [x] Existing tests cover changed behavior — justification: `test/changelog-docs.test.ts` validates the native changelog contract, including the version heading, MDX SPDX comment, and published routes. - [ ] Tests not applicable — justification: - [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: ## Documentation Writer Review - [x] Documentation writer subagent reviewed the completed changes - Result: `docs-updated` - Evidence: `docs/changelog/2026-07-29.mdx` was reviewed against `docs/CONTRIBUTING.md` and `WRITING.md` for release meaning, terminology, structure, voice, sentence form, MDX structure, published routes, and code-sample presentation. The changelog contract passed 6 tests. The docs build completed with 0 errors and 2 existing Fern warnings. - Agent: Codex CLI <!-- docs-review-head-sha: e3221d1 --> <!-- docs-review-agents-blob-sha: c052d60 --> ## DGX Station Hardware Evidence - [ ] Tested on DGX Station - Tested commit: Not applicable. `scripts/prepare-dgx-station-host.sh` is unchanged. - Station profile/scenario: Not applicable. - Result: Not applicable. - Supporting evidence: Not applicable. ## Verification - [x] PR description includes a `Signed-off-by:` line and every commit appears as `Verified` in GitHub - [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or `npm run validate:pr` passed after refreshing `origin/main` when hooks were skipped or unavailable - [x] Targeted behavior tests pass for the current change set, or tests are marked not applicable above — `npx vitest run test/changelog-docs.test.ts` passed 6 tests. - [ ] 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) — The build completed with 0 errors and 2 existing Fern warnings. - [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) — Native changelog entries use the required parser-safe MDX SPDX comment and do not use frontmatter. --- Signed-off-by: San Dang <sdang@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added managed Hermes upgrades with verified releases, version reporting, and preserved configuration contracts. - Improved Deep Agents Code JSON output and skill installation behavior. - Added clearer Docker host and system readiness reporting. - Improved post-reboot delivery recovery and sandbox readiness timing. - **Bug Fixes** - Preserved gateway state when uninstalling with `--keep-openshell`. - Prevented conflicting messaging credentials from blocking onboarding and rebuilds. - Improved gateway diagnostics, dependency security, runtime filesystem protection, and evidence handling. - **Documentation** - Published the v0.0.98 release notes. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Problem (#7227)
start's post-recreate recovery waits for OpenShell to re-register a just-recreated sandbox as Ready, then gives up after 30s and surfaces the manual-recover hint.connect's readiness wait (waitForSandboxReadyOrExit) proves the same post-recreate sandbox readiness but allows 120s (NEMOCLAW_CONNECT_TIMEOUT).On a cold start the sandbox can sit in a transient
phase: Errorsettling window that exceeds 30s but is comfortably within 120s. When it does, the recovery path abandons the sandbox and prints the manual-recover hint, whileconnect --probe-only— with the larger budget — recovers the exact same sandbox and starts the primary dashboard/API forward. That 4x budget asymmetry is the intermittent start/recovery failure in #7227.Change
GATEWAY_RECOVERY_WAIT_DEFAULT_SECONDS = 120and use it for both readiness-wait default sites (waitForRecreatedSandboxOpenShellReadyResultandwaitForRecoveredSandboxGateway), aligning them withconnect.NEMOCLAW_GATEWAY_RECOVERY_WAIT_SECONDS(existing env override) is unchanged.NEMOCLAW_GATEWAY_RECOVERY_SETTLE_SECONDS, 25s).Verification / honesty note
This is a low-probability cold-start race. On latest
mainit reproduced 1 in 12 start cycles on a DGX Spark and could not be re-triggered deterministically afterward (0 in a further 20 warm + cold retries). Because the timing is non-deterministic, this PR is a principled budget alignment (match the two paths that prove the same readiness) rather than an empirically-timed value — I could not produce a green/red toggle that flips solely on the 30→120 change.Given that, keeping #7227 open to confirm over repeated cold starts is reasonable; hence
Refsrather thanFixes.Tests
timeoutSecondsoption and no env override, a persistent transientphase: Erroris retried past the old 11-attempt (30s) cap — the 12th probe must still be reached. Would fail under the old 30s default.process-recoverysuite unchanged and green (42 tests).typecheck:cliandprekclean.Refs #7227
Signed-off-by: Yanyun Liao yanyunl@nvidia.com
Summary by CodeRabbit