Skip to content

fix(rebuild): fall back to host-side MCP recovery when --force and exec relay unavailable - #7195

Closed
kagura-agent wants to merge 1 commit into
NVIDIA:mainfrom
kagura-agent:fix/7062-force-rebuild-unreachable-mcp
Closed

fix(rebuild): fall back to host-side MCP recovery when --force and exec relay unavailable#7195
kagura-agent wants to merge 1 commit into
NVIDIA:mainfrom
kagura-agent:fix/7062-force-rebuild-unreachable-mcp

Conversation

@kagura-agent

@kagura-agent kagura-agent commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Problem

When a registered sandbox with managed MCP state has its exec relay permanently unavailable (sandbox reports Ready but openshell sandbox exec fails), rebuild --force cannot recover because prepareMcpForRebuild still requires the live exec relay to scrub the MCP adapter before deletion.

This leaves all supported recovery paths blocked:

  • rebuild --yes — cannot back up through the failed relay
  • rebuild --force — cannot scrub the managed MCP adapter through the failed relay
  • onboard --recreate-sandbox — refuses a sandbox that owns managed MCP servers
  • mcp remove --force — cannot prove complete cleanup

Closes #7062

Solution

Thread the force flag from the rebuild pipeline into prepareMcpForRebuild. When --force is set and the live MCP bridge preparation fails (because the exec relay is unavailable), fall back to prepareMcpBridgesForAbsentSandboxRebuild — the host-side-only recovery path that doesn't require sandbox exec.

This follows the existing pattern where --force already skips backup failures, extending it to also recover from exec relay failures during MCP preparation.

Changes

File Change
rebuild-mcp-phase.ts Add force: boolean param; catch live-path failure and fall back to absent-sandbox path when force=true
rebuild-destroy-phase.ts Add force?: boolean to RebuildDestroyPhaseInput; thread to prepareMcpForRebuild
rebuild-pipeline.ts Pass normalized.force into runRebuildDestroyPhase
rebuild-destroy-phase.test.ts Verify force=true is threaded to prepareMcpForRebuild

Testing

  • npx vitest run src/lib/actions/sandbox/rebuild-destroy-phase.test.ts — 2/2 pass
  • npx tsc --noEmit — clean (no new errors)
  • 4-file diff, 69 insertions, 1 deletion

Summary by CodeRabbit

  • New Features

    • Added force-mode support to the sandbox rebuild workflow.
    • Force mode now enables fallback recovery when MCP preparation encounters errors.
    • Improved failure handling with clear warnings and fallback error reporting.
  • Tests

    • Added coverage confirming that force mode is correctly passed through the rebuild and destroy phases.

…ec relay unavailable

When a sandbox reports Ready but its exec relay is broken,
`rebuild --force` now falls back to prepareMcpBridgesForAbsentSandboxRebuild
instead of bailing. This provides a recovery path for registered-but-unreachable
sandboxes with managed MCP state.

Closes NVIDIA#7062
@copy-pr-bot

copy-pr-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: cefec5dc-ed68-4b29-9d64-819a0366a5ec

📥 Commits

Reviewing files that changed from the base of the PR and between 78e0e4e and a5c19d9.

📒 Files selected for processing (4)
  • src/lib/actions/sandbox/rebuild-destroy-phase.test.ts
  • src/lib/actions/sandbox/rebuild-destroy-phase.ts
  • src/lib/actions/sandbox/rebuild-mcp-phase.ts
  • src/lib/actions/sandbox/rebuild-pipeline.ts

📝 Walkthrough

Walkthrough

The rebuild pipeline now propagates force through the destroy phase into MCP preparation. Forced preparation can recover MCP bridges from the host when sandbox-side preparation fails, with fallback failure handling and test coverage.

Changes

Forced MCP recovery

Layer / File(s) Summary
Force propagation through rebuild phases
src/lib/actions/sandbox/rebuild-pipeline.ts, src/lib/actions/sandbox/rebuild-destroy-phase.ts, src/lib/actions/sandbox/rebuild-mcp-phase.ts
The normalized force setting is passed through rebuild destruction into the expanded prepareMcpForRebuild signature.
Host-side MCP fallback and coverage
src/lib/actions/sandbox/rebuild-mcp-phase.ts, src/lib/actions/sandbox/rebuild-destroy-phase.test.ts
When forced preparation fails outside stale recovery, host-side bridge preparation is attempted; fallback failure re-locks shields and calls bail, while tests cover the force argument and mocked dependencies.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant rebuildPipeline as rebuild-pipeline
  participant rebuildDestroyPhase as rebuild-destroy-phase
  participant prepareMcpForRebuild
  participant hostRecovery as prepareMcpBridgesForAbsentSandboxRebuild
  rebuildPipeline->>rebuildDestroyPhase: pass normalized.force
  rebuildDestroyPhase->>prepareMcpForRebuild: pass force
  prepareMcpForRebuild->>hostRecovery: attempt host-side recovery after error
  hostRecovery-->>prepareMcpForRebuild: recovery result
Loading

Possibly related PRs

Suggested labels: area: sandbox, bug-fix

Suggested reviewers: cv, ericksoa

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: force-enabled fallback to host-side MCP recovery when exec relay is unavailable.
Linked Issues check ✅ Passed The changes implement the requested --force recovery path for unreachable managed-MCP sandboxes by falling back to host-side preparation.
Out of Scope Changes check ✅ Passed The modified files stay focused on rebuild force propagation, MCP recovery logic, and the supporting test coverage.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Blocking findings reported

Advisor assessment: Blockers require maintainer review
Next action: Review the blockers below.
Findings: 1 blocker · 0 warnings · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · high confidence · 1 blocker · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · high confidence · 2 blockers · 3 warnings · 1 suggestion
  • Model comparison: normalized findings differ; normalized E2E selections differ; Nemotron reported 1 more blocker, 3 more warnings, 1 more suggestion.

Nemotron output stays in workflow artifacts and does not change the assessment above.

E2E guidance

Advisory only. E2E / PR Gate selects and runs jobs independently.

Recommended E2E: onboard-repair, onboard-resume, state-backup-restore, upgrade-stale-sandbox

2 optional E2E recommendations
  • mcp-bridge
  • sandbox-rebuild

Blockers

PRA-1 Blocker — Retain effective-policy validation before force fallback

  • Location: src/lib/actions/sandbox/rebuild-mcp-phase.ts:32
  • Category: correctness
  • Problem: The new catch falls back to absent-sandbox preparation for every live preparation error while the sandbox is still treated as present. That helper checks registry policy ownership but deliberately skips `assertGeneratedPolicyMutationSafe`, so an unreachable or drifted effective generated policy can proceed to sandbox deletion under `--force`, despite the normal rebuild path refusing to mutate in that state.
  • Impact: A forced rebuild can delete a live sandbox after bypassing the ownership and effective-policy guard that prevents mutation when an MCP policy is drifted or cannot be inspected, weakening the transactional safety boundary for managed MCP recovery.
  • Fix: Keep the live effective-policy safety check fail-closed before taking the host-side fallback, or limit fallback to a specifically identified relay-unavailable condition and separately preserve equivalent policy-state validation before deletion.
  • Verification: Read `prepareMcpBridgesForRebuild` and `prepareMcpBridgesForAbsentSandboxRebuild` in `src/lib/actions/sandbox/mcp-bridge-rebuild.ts`, then confirm a force rebuild with a registered generated policy whose gateway state is unreachable or drifted aborts before `openshell sandbox delete`.
  • Test coverage: Add a rebuild test that makes live MCP preparation fail while the generated policy is unreachable or drifted, invokes `--force`, and asserts no sandbox delete or fallback destructive transition occurs.
  • Evidence: `src/lib/actions/sandbox/rebuild-mcp-phase.ts:32-35` catches any live preparation error and calls `prepareMcpBridgesForAbsentSandboxRebuild` when `force && !staleRecovery`. `src/lib/actions/sandbox/mcp-bridge-rebuild.ts:77-82` performs `assertGeneratedPolicyMutationSafe` only in live preparation; absent preparation at `:94-97` uses only `assertGeneratedPolicyRegistrationMutationSafe`. `src/lib/actions/sandbox/mcp-bridge-policy.ts:202-219` states that unowned, unreachable, or drifted generated policy must refuse adapter/provider/live-policy mutation until ownership is resolved.

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

@apurvvkumaria

Copy link
Copy Markdown
Collaborator

Superseded by #7196. The replacement preserves this implementation with explicit Co-authored-by credit to @kagura-agent, narrows host-side recovery to a failed pre-mutation sandbox no-op, adds fail-closed regressions and docs, and provides a compliant signed DCO history. Closing this duplicate so review and CI converge on the replacement.

@kagura-agent

Copy link
Copy Markdown
Contributor Author

Thanks for the credit and the improved approach — the pre-mutation exec probe is much cleaner than my catch-all fallback. Noted the DCO sign-off requirement for future PRs.

cv pushed a commit that referenced this pull request Jul 26, 2026
## Summary

An explicit `rebuild --force` can now preserve registered managed MCP
intent when the old sandbox cannot execute a pre-mutation no-op. The
recovery does not reinterpret arbitrary live MCP preparation failures as
exec-relay loss, and it preserves the original contribution from
@kagura-agent with co-author credit.

## Related Issue

Closes #7062.

Supersedes #7195 because its published commit lacks the required DCO
sign-off and cannot be repaired append-only.

## Changes

- Thread the normalized force choice through the rebuild destroy phase.
- Probe sandbox execution before any MCP teardown mutation.
- Use the existing host-side absent-sandbox recovery only when that
probe fails under explicit force.
- Keep policy drift, ambiguous ownership, invalid targets, provider
failures, and errors after a successful probe fail-closed.
- Require delete convergence to prove explicit absence for the named
sandbox; reject other-resource, mixed, and signal-terminated
diagnostics.
- Document the data-loss and managed-MCP recovery boundary in the
command reference and rebuild recovery guide.
- Cover force propagation, unavailable execution, live-path safety
failures, ambiguous host-side state, non-force behavior, and established
stale recovery.

## 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

- [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 review
narrowed recovery to a pre-mutation no-op failure and added fail-closed
regressions.
- [ ] 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: `no-docs-needed`
- Evidence: The writer reviewed the cumulative behavior through
`e92c7f060896fe3ea5fb84cc4876ddba26c8fcf9`, then independently reviewed
the exact follow-up delta through
`768e87c20a6f676e51bf6890884d724d76565a3a`. The follow-up changes only
three integration-test diagnostics to name sandbox `my-assistant`,
aligning intended success fixtures with the already-documented strict
delete-convergence rule. No command, flag, output contract, recovery
step, runtime behavior, or user action changed.
- Agent: Codex Desktop
<!-- docs-review-head-sha: 768e87c -->
<!-- docs-review-agents-blob-sha: be20a09 -->

## 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 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 — exact head
`768e87c20a6f676e51bf6890884d724d76565a3a`: 12 remaining integration
fixture tests, 26 owning destroy-phase tests, and 96 earlier affected
fixture-consumer tests passed; Biome, the CLI build, CLI type-check,
normal commit hooks, and normal push hooks passed. The earlier branch
head retained its broader 90 owning rebuild-flow, 32 adjacent CLI, and
45 MCP lifecycle integration test evidence.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — not applicable to this narrow branch;
exact-head PR CI will run the repository gates.
- [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
prior head's documentation validation passed with 0 errors and 2 Fern
warnings; the exact-head follow-up changes no documentation.
- [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: Apurv Kumaria <akumaria@nvidia.com>


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

* **Documentation**
* Expanded the `rebuild --force` managed-MCP warning with clearer
guidance on when recovery falls back to a host-side, fail-closed path,
plus safer post-delete verification and reconciliation outcomes.

* **Bug Fixes**
* Improved forced managed-MCP rebuild safety by probing in-sandbox when
enabled, using stricter read-only ownership/policy checks when exec is
unavailable, handling ambiguous delete states correctly, and delaying
local NIM stopping until after deletion is confirmed.

* **Tests**
* Added broader coverage for forced rebuild MCP prep, exec-unavailable
recovery, policy/ownership drift detection, and correct `force` behavior
through the rebuild destroy phase.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Co-authored-by: kagura-agent <kagura.agent.ai@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(rebuild): --force cannot recover an unreachable sandbox with managed MCP state

2 participants