fix(sandbox): serialize live create handoff - #8729
Conversation
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
📝 WalkthroughWalkthroughThe native GPU sandbox creation flow now defers runtime patching for restart-safe no-GPU recreation until readiness termination. The test verifies persisted startup settings, readiness waiting, and patch application after create-process completion. ChangesRestart-safe recreation
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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 `@src/lib/onboard/sandbox-gpu-create-flow.test.ts`:
- Around line 539-549: Update the sandbox creation test around
streamSandboxCreate so its mock invokes the captured onPoll callback before the
stream promise resolves, rather than calling it afterward in the test body.
Assert the behavioral order of the poll, stream completion, and ensureApplied(),
while verifying maybeApplyDuringCreate() is skipped; avoid assertions that
depend on implementation-specific call structure.
🪄 Autofix
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: cebd8bbc-375e-47cd-84e3-f5a5e5878bf9
📒 Files selected for processing (2)
src/lib/onboard/sandbox-gpu-create-flow.test.tssrc/lib/onboard/sandbox-gpu-create-run-attempt.ts
| expect(mocks.streamSandboxCreate).toHaveBeenCalledWith( | ||
| "openshell", | ||
| ["sandbox", "create"], | ||
| input.sandboxEnv, | ||
| expect.objectContaining({ waitForReadyTermination: true }), | ||
| ); | ||
| const onPoll = mocks.streamSandboxCreate.mock.calls[0]?.[3]?.onPoll; | ||
| expect(onPoll).toBeTypeOf("function"); | ||
| onPoll(); | ||
| expect(patch.maybeApplyDuringCreate).not.toHaveBeenCalled(); | ||
| expect(patch.ensureApplied).toHaveBeenCalledOnce(); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Exercise onPoll before the stream resolves.
The explicit call at Line 547 occurs after the stream invocation in the test body. It does not prove that an active create poll skips maybeApplyDuringCreate() or that ensureApplied() runs after ownership release. Configure the stream mock to invoke onPoll before it resolves, then assert the order: poll, stream completion, ensureApplied().
As per path instructions, review tests for behavioral confidence rather than implementation lock-in.
🤖 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/sandbox-gpu-create-flow.test.ts` around lines 539 - 549,
Update the sandbox creation test around streamSandboxCreate so its mock invokes
the captured onPoll callback before the stream promise resolves, rather than
calling it afterward in the test body. Assert the behavioral order of the poll,
stream completion, and ensureApplied(), while verifying maybeApplyDuringCreate()
is skipped; avoid assertions that depend on implementation-specific call
structure.
Source: Path instructions
PR Review Advisor — No blocking findings reportedAdvisor assessment: No blocking advisor findings reported Model lanes
3 additional E2E selections from the second opinionAdvisory only. The primary lane did not select these E2E jobs or targets.
Second-opinion terminology and E2E selections are advisory. Live E2E does not run automatically for pull requests. 2 semantic terminology decisionsTerminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.
E2E guidanceAdvisory only. A maintainer can dispatch the default E2E suite against this exact revision. Recommended E2E: This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge. |
<!-- markdownlint-disable MD041 --> ## Summary Tests now exercise the serialized create handoff added by #8729 at the actual lifecycle boundary. This also fixes the late shard-12 failure where the integration fixture never reported that its fake create process exited after `SIGTERM`. ## Related Issue Follow-up to #8729 and its [CodeRabbit ordering finding](#8729 (comment)). ## Changes - Invoke the captured create poll before the mocked stream resolves and assert the poll, stream completion, and deferred `ensureApplied()` order. - Make the existing process-group fixture emit the fake create child's close event after `SIGTERM`, matching the ownership-release contract. - Assert that the waited-for stream is not detached, with no production-code changes or new test files. ## Type of Change - [x] 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 <!-- Check 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: - [ ] Docs updated for user-facing behavior changes - [x] Docs not applicable — justification: Test fixtures now match the already-merged ownership contract; no production behavior or user-facing surface changes. - [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: Test-only changes preserve the fail-closed create timeout, simulate only the expected process exit, and do not alter production lifecycle, rollback, readiness, or compatibility behavior. - [ ] Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue: ## Documentation Writer Review <!-- Required for code and documentation changes after the changes and applicable validation are complete. Keep one review checkbox and one instance of each visible or hidden field. For Evidence, list changed documentation paths. For documentation-only changes, also state that the writing rules and documentation style were reviewed. For other results, explain why no documentation change is needed or why the review is blocked. For Agent, use a consistent product and surface name, such as Codex Desktop, Codex CLI, Claude Code, or Cursor. After committing all review changes, put `git rev-parse --short HEAD` and `git rev-parse --short HEAD:AGENTS.md` in the hidden metadata below. Rerun the review and refresh that metadata after any new commit. This receipt is advisory during the data-collection pilot. --> - [x] Documentation writer subagent reviewed the completed changes - Result: `no-docs-needed` - Evidence: No documentation paths changed. Existing `docs/get-started/quickstart.mdx` and `docs/reference/commands.mdx` already describe the unchanged ready and recreation contract. - Agent: Codex Desktop <!-- docs-review-head-sha: 70160ea --> <!-- docs-review-agents-blob-sha: c4923a3 --> ## DGX Station Hardware Evidence <!-- Required only when scripts/prepare-dgx-station-host.sh changes. Maintainers must review the linked evidence before approving or merging. This is human-reviewed evidence, not authenticated hardware provenance. Exceptional bypasses use existing repository governance and must be documented on the PR. --> - [ ] Tested on DGX Station - Tested commit: - Station profile/scenario: - Result: - Supporting evidence: ## 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 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 — command/result or justification: `npx vitest run --project cli src/lib/onboard/sandbox-gpu-create-flow.test.ts src/lib/sandbox/create-stream.test.ts` (56 passed); `npx vitest run --project integration test/onboard-sandbox-recreation.test.ts -t "waits for the create stream to close"` (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: Not applicable; this is a two-test fixture correction protected by targeted tests and normal hooks. - [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) - [ ] 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) --- <!-- DCO sign-off is required in this PR description, and every commit must appear as Verified in GitHub. Run: git config user.name && git config user.email --> Signed-off-by: Apurv Kumaria <akumaria@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Improved coverage for restarting and recreating GPU-enabled sandboxes safely. * Verified that updates are applied only after sandbox creation completes. * Strengthened readiness and cleanup checks for sandbox creation processes. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Summary
Live onboarding now waits for the OpenShell create client to release ownership before applying restart-safe Docker recreation. Previously the active onboarding path bypassed the existing ownership barrier, so recreation could race the still-running create process and leave fresh sandboxes unready.
Related Issue
Follow-up to #8720. This is complementary to the stopped-sandbox recovery change in #8728.
Changes
streamSandboxCreate's existingwaitForReadyTerminationbarrier in the active unmanaged, non-compatibility restart-safe path.ensureApplied()cutover runs only after create ownership is released.Type of Change
Quality Gates
Documentation Writer Review
no-docs-neededdocs/reference/commands.mdxanddocs/get-started/quickstart.mdxalready own the unchanged create, ready, and dashboard contract.DGX Station Hardware Evidence
Verification
Signed-off-by:line and every commit appears asVerifiedin GitHubpre-commit,commit-msg, andpre-pushhooks passed, ornpm run validate:prpassed after refreshingorigin/mainwhen hooks were skipped or unavailablenpx vitest run --project cli src/lib/onboard/sandbox-gpu-create-flow.test.ts src/lib/sandbox/create-stream.test.ts(56 passed);npm run typecheck:clipassed.npm testfor broad runtime/test-harness changes;npm run checkfor repo-wide validation/coverage changes — command/result: Not applicable; the change is a focused two-file onboarding sequencing fix covered by targeted tests and normal hooks.npm run docsbuilds without warnings (doc changes only)Signed-off-by: Apurv Kumaria akumaria@nvidia.com