fix(tunnel): release NemoClaw gateway port on stop (#5968) - #5988
Conversation
`nemoclaw stop` (the deprecated alias for `tunnel stop`) only stopped the in-sandbox channels and the host-side cloudflared tunnel. On macOS the OpenShell gateway runs as a host `openshell-gateway` process bound to the gateway port (default 8080), and nothing in the stop path stopped it — so the port stayed occupied after `nemoclaw stop` and a fresh onboard / port-conflict recovery could not re-bind it. `stopAll` now releases the NemoClaw-managed gateway port via a new `gateway-port-release` helper. It reuses the shared host-gateway stopper (`stopHostGatewayProcesses`) rather than an ad-hoc pkill: it stops the recorded gateway process (pid file) plus any duplicate/orphan gateway squatting the same port (discovered with `lsof`, covering the reporter's `host-process=2` case), then polls the port for release. The sweep is scoped to the resolved gateway port and gated on the openshell-gateway cmdline, so a different worktree's gateway or an unrelated process is never torn down. The remediation warning fires only when a matched gateway process resists stopping, so a Docker-published port held by docker-proxy is not mislabeled. Release is best-effort: a stop never fails because gateway teardown hit an edge case. Fixes #5968 Signed-off-by: Yimo Jiang <yimoj@nvidia.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds managed gateway port release on stop, Docker-driver prelaunch reaping and cutover orchestration, plus tests, CI, and docs updates. ChangesGateway Lifecycle
Docker-driver Cutover
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant runStopCommand
participant stopAll
participant releaseManagedGatewayPort
participant resolveStopGatewayPort
participant listeningGatewayPids
participant stopHostGatewayProcesses
participant confirmGatewayPortReleased
runStopCommand->>stopAll: stopAll({ sandboxName, releaseGatewayPort })
stopAll->>releaseManagedGatewayPort: releaseGatewayPortForStop(sandboxName)
releaseManagedGatewayPort->>resolveStopGatewayPort: resolve port
resolveStopGatewayPort-->>releaseManagedGatewayPort: port or null
releaseManagedGatewayPort->>listeningGatewayPids: scan listeners
releaseManagedGatewayPort->>stopHostGatewayProcesses: stop scoped PIDs
stopHostGatewayProcesses-->>releaseManagedGatewayPort: stopped / failed
releaseManagedGatewayPort->>confirmGatewayPortReleased: confirm released
confirmGatewayPortReleased-->>releaseManagedGatewayPort: released / remaining
sequenceDiagram
participant startDockerDriverGateway
participant createDockerDriverGatewayRuntimeHelpers
participant runDockerDriverGatewayCutover
participant reapHostGatewayBeforeLaunchOrFail
participant reapDuplicateHostGatewaysExceptOrFail
startDockerDriverGateway->>createDockerDriverGatewayRuntimeHelpers: build helpers
startDockerDriverGateway->>runDockerDriverGatewayCutover: run cutover
runDockerDriverGatewayCutover->>reapHostGatewayBeforeLaunchOrFail: reap before launch
runDockerDriverGatewayCutover->>reapDuplicateHostGatewaysExceptOrFail: reap duplicates on reuse
runDockerDriverGatewayCutover-->>startDockerDriverGateway: reused or launch
Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Code Coverage OverviewLanguages: TypeScript TypeScript / code-coverage/pluginThe overall coverage in the Show a code coverage summary of the most covered files.
TypeScript / code-coverage/cliThe overall coverage in the Show a code coverage summary of the most covered files.
Updated |
E2E verification (real worktree CLI)The issue is a host This exercises the full new path: |
PR Review Advisor — No blocking findingsMerge posture: No blocking advisor findings 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. |
E2E Advisor RecommendationRequired E2E: Dispatch hint: Full advisor summaryE2E Recommendation AdvisorBase: Required E2E
Optional E2E
New E2E recommendations
Dispatch hint
|
Vitest E2E Scenario RecommendationRequired Vitest E2E scenarios: Dispatch required Vitest E2E scenarios:
Full Vitest E2E advisor summaryVitest E2E Scenario AdvisorBase: Required Vitest E2E scenarios
Optional Vitest E2E scenarios
Relevant changed files
|
PR Review Advisor (Nemotron Ultra) — Changes requestedMerge posture: Do not merge yet Action checklist
Findings index
🚨 Required before mergeAddress these before merging unless a maintainer explicitly overrides the advisor with rationale.
|
The codebase-growth-guardrails check forbids adding `if` statements in changed test files. Rewrite the lsofResponder helper to branch with a ternary instead, keeping behavior identical. Signed-off-by: Yimo Jiang <yimoj@nvidia.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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/tunnel/gateway-port-release.test.ts`:
- Around line 61-65: The new conditional in the test helper is unnecessary and
is causing CI issues; remove the `if (command !== "lsof") return ok();` branch
from the `run` stub in `gateway-port-release.test.ts` so the helper always
follows the injected `lsof` probe behavior. Keep the existing response selection
logic using `state.calls`, `responses`, and `ok()` unchanged so the test
coverage remains the same while eliminating the branch.
In `@src/lib/tunnel/gateway-port-release.ts`:
- Around line 229-237: The release confirmation in gateway-port-release.ts is
treating a failed listening probe as success by coercing null from
listeningPids() into an empty array inside the waitUntil predicate. Update the
logic around waitUntil and the released/remaining handling so that a lsof error
does not count as a released port; only consider the port released when
listeningPids() returns a real empty list, and preserve null/error cases so they
can be retried or surfaced instead of being mistaken for success.
- Around line 121-129: The fallback in gateway port resolution is swallowing
malformed sandbox binding errors and incorrectly returning the process-wide
default port. Update resolveGatewayPortFromName() handling in
gateway-port-release so it only falls back when no sandbox entry exists or the
lookup is genuinely absent, and let resolveSandboxGatewayName() failures
propagate to the caller. Keep the boundary handling in stopAll({ sandboxName })
so invalid persisted bindings fail the sandbox-specific release instead of
retargeting the default gateway.
In `@src/lib/tunnel/services.ts`:
- Around line 629-630: The gateway-port release in services.ts should not fall
back to the process-wide default when no sandbox identity is available. Update
the stopAll({ pidDir }) flow around releaseManagedGatewayPort so it only
releases a managed gateway port when sandboxName was resolved, and otherwise
skip the release entirely rather than passing {}. Use the existing sandboxName
check near the releaseManagedGatewayPort call to keep the teardown scoped to the
pidDir-selected service.
🪄 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: 5b87f353-171b-4cf0-91be-92852de2a7a9
📒 Files selected for processing (4)
src/lib/tunnel/gateway-port-release.test.tssrc/lib/tunnel/gateway-port-release.tssrc/lib/tunnel/services.test.tssrc/lib/tunnel/services.ts
…stop Addresses PR Review Advisor PRA-1/PRA-2: `resolveStopGatewayPort` previously caught any error from `resolveSandboxGatewayName` and fell back to the process-wide `GATEWAY_PORT`. For a corrupt or tampered registry row that silently retargeted the destructive stop path (pid-file derivation, lsof scan, signal delivery) at the default gateway — potentially another sandbox's or worktree's `openshell-gateway`. Now resolution returns null when a sandbox *has* a persisted gateway binding that fails validation, and `releaseManagedGatewayPort` skips the destructive path entirely (no lsof, no stopHostGatewayProcesses) with a warning. The legacy/no-registry fallback to `GATEWAY_PORT` is preserved only for a missing entry or a legacy entry with no gateway fields, mirroring the fail-closed contract of `resolveSandboxGatewayName`. Adds regression tests: fail-closed port resolution, invalid-binding skip (no default-port cleanup), non-matching listener left alone without sudo remediation, and lsof real-failure pid-file fallback. Signed-off-by: Yimo Jiang <yimoj@nvidia.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Response to PR Review Advisor (run on
|
…nfirm probe Addresses two CodeRabbit findings: - services.ts: `stopAll` now only releases the gateway when a sandbox identity was resolved. With no sandbox name the port resolver would fall back to the process-wide default gateway port — not tied to the selected pidDir — which could tear down another worktree's default gateway. Skip the release instead. - gateway-port-release.ts: a transient `lsof` failure during the confirmation poll previously coerced `null` to `[]`, reporting the port as released without ever confirming it was free. The poll now tracks a failed probe and refuses to report released on an lsof error. Updates/adds tests: stop skips release when no sandbox name resolves, and a failed confirmation probe is not reported as a released port. Signed-off-by: Yimo Jiang <yimoj@nvidia.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re: PRA-3 / PRA-4
|
Addresses PR Review Advisor PRA-3: `lazyGetSandbox` previously caught a registry read error and returned null, which `resolveStopGatewayPort` then treated as a clean "no entry" and fell back to destructive default-port cleanup. A corrupt/unreadable registry now propagates and is handled as a fail-closed skip (no lsof, no stopHostGatewayProcesses), the same as an invalid persisted binding. Adds tests for the lookup-throws path at both the resolver and releaseManagedGatewayPort layers; widens the skip warning to cover "invalid or unreadable". Signed-off-by: Yimo Jiang <yimoj@nvidia.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Advisor items — consolidated status (head
|
Advisor items (refreshed numbering on
|
|
✨ |
…ndbox
resolveStopGatewayPort() coerced a *named* stop whose registry entry was
absent to the process-wide GATEWAY_PORT, so `nemoclaw stop --sandbox
<unknown>` could scan and signal the default `openshell-gateway` that
belongs to another sandbox/worktree — the same hazard stopAll() already
avoids for the no-sandbox path. Fail closed (skip) instead, while still
honoring a real legacy entry (e.g. `{}` → base `nemoclaw` → default port)
and the explicit no-sandbox-name default-cleanup call. Addresses the PR
Review Advisor PRA-5 security finding.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
Advisor response (head
|
…lease Commit the runtime/integration test the advisor asked for (PRA-2 / the runtime-validation test follow-ups): instead of mocks, it launches a real process whose argv0 basename is `openshell-gateway` (the identity the host stopper cmdline-gates on) bound to an isolated non-default port with an isolated HOME/state dir, runs the REAL releaseManagedGatewayPort (real spawnSync/ps/kill/stopper), then proves a fresh process can immediately rebind the freed port — the exact #5968 macOS failure mode. The fake gateway is launched via a short-lived launcher that exits so the gateway orphans to init (avoiding an unreaped zombie under the synchronous, event-loop-blocked release call). POSIX-gated via it.skipIf and written branch-free to satisfy the changed-test conditionals budget. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
Runtime validation added (head
|
E2E Target RecommendationRequired E2E targets: Dispatch required E2E targets:
Full E2E target advisor summaryE2E Target AdvisorBase: Required E2E targets
Optional E2E targets
Relevant changed files
|
resolveStopGatewayPort() ignored an out-of-range explicit `port` override (via `isValidPort` being false) and silently fell through to the sandbox binding / default `GATEWAY_PORT`. An explicitly provided but invalid port is a caller error, so distinguish it from an absent override and fail closed (return null → releaseManagedGatewayPort skips/warns), consistent with the fail-closed handling already used for invalid registry state. Addresses the PR Review Advisor PRA-1 correctness finding. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
PRA-1 (invalid explicit port override) fixed (head
|
Disposition of remaining advisor items (head
|
|
🌿 Preview your docs: https://nvidia-preview-pr-5988.docs.buildwithfern.com/nemoclaw |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/macos-e2e.yaml (1)
73-78: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueConsider a step-level timeout for the real-process integration step.
This step runs
test/tunnel-gateway-port-release-runtime.test.ts, which spawns a realopenshell-gateway-like process and probes port release vialsof/polling. If cleanup ever hangs (e.g., zombie process not reaped), this step could consume the full 30-minute job timeout, delaying failure signal for the rest of the job. A tightertimeout-minuteson just this step would fail fast.💡 Optional: add a step timeout
- name: Run gateway lifecycle regressions + timeout-minutes: 10 run: >- npx vitest run --project integration test/tunnel-gateway-port-release-runtime.test.ts test/onboard-gateway-prelaunch-cutover.test.ts🤖 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 @.github/workflows/macos-e2e.yaml around lines 73 - 78, The real-process integration step in the macOS workflow can hang and consume the full job timeout, so add a step-level timeout to the “Run gateway lifecycle regressions” step that runs the integration vitest command. Update the workflow step that executes test/tunnel-gateway-port-release-runtime.test.ts and test/onboard-gateway-prelaunch-cutover.test.ts so it fails fast if cleanup or process reaping stalls, while leaving the rest of the job unaffected.
🤖 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.
Nitpick comments:
In @.github/workflows/macos-e2e.yaml:
- Around line 73-78: The real-process integration step in the macOS workflow can
hang and consume the full job timeout, so add a step-level timeout to the “Run
gateway lifecycle regressions” step that runs the integration vitest command.
Update the workflow step that executes
test/tunnel-gateway-port-release-runtime.test.ts and
test/onboard-gateway-prelaunch-cutover.test.ts so it fails fast if cleanup or
process reaping stalls, while leaving the rest of the job unaffected.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: dc2f46c7-143c-4384-915c-7a9ac00604ff
📒 Files selected for processing (4)
.github/workflows/macos-e2e.yamlci/platform-matrix.jsondocs/inference/inference-options.mdxdocs/reference/platform-support.mdx
✅ Files skipped from review due to trivial changes (1)
- ci/platform-matrix.json
Vitest E2E Target Results — ❌ Some jobs failedRun: 28681019834
|
Vitest E2E Target Results —
|
| Job | Result |
|---|---|
| agent-turn-latency | |
| bedrock-runtime-compatible-anthropic | |
| brave-search | |
| channels-add-remove | |
| channels-stop-start | |
| cloud-inference | |
| cloud-onboard | |
| common-egress-agent | |
| concurrent-gateway-ports | |
| credential-migration | |
| credential-sanitization | |
| cron-preflight-inference-local | |
| device-auth-health | |
| diagnostics | |
| docs-validation | |
| double-onboard | |
| full-e2e | |
| gateway-drift-preflight | |
| gateway-guard-recovery | |
| gateway-health-honest | |
| gpu-double-onboard | |
| gpu-e2e | |
| hermes-dashboard | |
| hermes-discord | |
| hermes-e2e | |
| hermes-gpu-startup | |
| hermes-inference-switch | |
| hermes-slack | |
| inference-routing | |
| issue-2478-crash-loop-recovery | |
| issue-4434-tui-unreachable-inference | |
| issue-4462-scope-upgrade-approval | |
| jetson-nvmap-gpu | |
| kimi-inference-compat | |
| launchable-smoke | |
| live | |
| messaging-compatible-endpoint | |
| messaging-providers | |
| model-router-provider-routed-inference | |
| network-policy | |
| ollama-auth-proxy | |
| onboard-negative-paths | |
| onboard-repair | |
| onboard-resume | |
| openclaw-discord-pairing | |
| openclaw-inference-switch | |
| openclaw-skill-cli | |
| openclaw-slack-pairing | |
| openclaw-tui-chat-correlation | |
| openshell-gateway-auth-contract | |
| openshell-gateway-upgrade | |
| openshell-version-pin | |
| overlayfs-autofix | |
| rebuild-hermes | |
| rebuild-hermes-stale-base | |
| rebuild-openclaw | |
| sandbox-operations | |
| sandbox-rebuild | |
| sandbox-rlimits-connect | |
| sandbox-survival | |
| security-posture | |
| sessions-agents-cli | |
| shields-config | |
| skill-agent | |
| snapshot-commands | |
| spark-install | |
| state-backup-restore | |
| telegram-injection | |
| token-rotation | |
| tunnel-lifecycle | |
| upgrade-stale-sandbox |
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Vitest E2E Target Results —
|
| Job | Result |
|---|---|
| cloud-onboard | |
| concurrent-gateway-ports | |
| double-onboard | |
| full-e2e | |
| gateway-drift-preflight | ✅ success |
| gateway-health-honest | ✅ success |
| tunnel-lifecycle |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
test/onboard-gateway-prelaunch-cutover.test.ts (1)
160-173: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueTest doesn't actually exercise drift-based exclusion.
cleanupPidsis alwaysportListenerPidsregardless ofdriftPids(seerunDockerDriverGatewayCutover), so this test passes for the same reason as the preceding "never includes an unobserved pid-file process" test (line 149) — the pid-file PID (4242) is excluded because it's unobserved by the listener scan, not because of drift. The title implies drift causes exclusion, but drift status has no bearing oncleanupPidsscoping in this code path.As per path instructions, "Flag copied production algorithms, broad mocks that bypass the behavior under test, and conditionals that make a test pass without exercising its claim."
🤖 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 `@test/onboard-gateway-prelaunch-cutover.test.ts` around lines 160 - 173, The test in onBoard-gateway-prelaunch-cutover should not claim drift-based exclusion when it never exercises that path. Update the "also excludes a drifted pid-file process from port-scoped cleanup" case around makeHarness/run so it explicitly validates the behavior driven by driftPids or rename the test to match the actual unobserved-PID exclusion being asserted. Make sure the assertion and setup in harness.events and cleanupPids/portListenerPids align with the behavior under test, rather than passing for the same reason as the previous pid-file exclusion test.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-nemohermes.mdx`:
- Line 1614: The Markdown/MDX text in the `nemohermes stop` description combines
multiple sentences on one line, violating the one-sentence-per-line guideline.
Update the affected prose in the `nemohermes stop` documentation block so each
sentence is on its own line, keeping the same wording but splitting it into
separate lines for the full stop behavior, tunnel services, and managed host
gateway port details.
---
Nitpick comments:
In `@test/onboard-gateway-prelaunch-cutover.test.ts`:
- Around line 160-173: The test in onBoard-gateway-prelaunch-cutover should not
claim drift-based exclusion when it never exercises that path. Update the "also
excludes a drifted pid-file process from port-scoped cleanup" case around
makeHarness/run so it explicitly validates the behavior driven by driftPids or
rename the test to match the actual unobserved-PID exclusion being asserted.
Make sure the assertion and setup in harness.events and
cleanupPids/portListenerPids align with the behavior under test, rather than
passing for the same reason as the previous pid-file exclusion test.
🪄 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: 9e09a135-6ec4-43ab-8698-c4a2cf167db2
📒 Files selected for processing (25)
docs/reference/commands-nemohermes.mdxdocs/reference/commands.mdxsrc/commands/simple-global-oclif-adapters.test.tssrc/commands/stop.tssrc/lib/onboard.tssrc/lib/onboard/docker-driver-gateway-cutover.tssrc/lib/onboard/docker-driver-gateway-port-listener.tssrc/lib/onboard/docker-driver-gateway-prelaunch.test.tssrc/lib/onboard/docker-driver-gateway-prelaunch.tssrc/lib/onboard/docker-driver-gateway-runtime.test.tssrc/lib/onboard/docker-driver-gateway-runtime.tssrc/lib/tunnel/gateway-port-confirmation.tssrc/lib/tunnel/gateway-port-listeners.tssrc/lib/tunnel/gateway-port-release-fail-closed.test.tssrc/lib/tunnel/gateway-port-release-lifecycle.test.tssrc/lib/tunnel/gateway-port-release-test-helpers.tssrc/lib/tunnel/gateway-port-release.tssrc/lib/tunnel/gateway-port-resolution.tssrc/lib/tunnel/service-command.test.tssrc/lib/tunnel/service-command.tssrc/lib/tunnel/services-gateway-ownership.test.tssrc/lib/tunnel/services.tstest/cli/tunnel-command.test.tstest/onboard-gateway-prelaunch-cutover.test.tstest/tunnel-gateway-port-release-runtime.test.ts
✅ Files skipped from review due to trivial changes (2)
- src/commands/simple-global-oclif-adapters.test.ts
- docs/reference/commands.mdx
🚧 Files skipped from review as they are similar to previous changes (2)
- src/lib/onboard/docker-driver-gateway-prelaunch.test.ts
- test/tunnel-gateway-port-release-runtime.test.ts
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Vitest E2E Target Results —
|
| Job | Result |
|---|---|
| cloud-onboard | ✅ success |
| concurrent-gateway-ports | ✅ success |
| double-onboard | |
| full-e2e | ✅ success |
| gateway-drift-preflight | ✅ success |
| gateway-health-honest | ✅ success |
| tunnel-lifecycle | ✅ success |
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Vitest E2E Target Results —
|
| Job | Result |
|---|---|
| cloud-onboard | |
| concurrent-gateway-ports | ✅ success |
| double-onboard | |
| full-e2e | ✅ success |
| gateway-drift-preflight | ✅ success |
| gateway-health-honest | ✅ success |
| tunnel-lifecycle | ✅ success |
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Vitest E2E Target Results —
|
| Job | Result |
|---|---|
| cloud-onboard | ✅ success |
| concurrent-gateway-ports | ✅ success |
| double-onboard | |
| full-e2e | ✅ success |
| gateway-drift-preflight | ✅ success |
| gateway-health-honest | ✅ success |
| tunnel-lifecycle | ✅ success |
E2E Target Results —
|
| Job | Result |
|---|---|
| cloud-onboard | |
| concurrent-gateway-ports | |
| double-onboard | |
| full-e2e | |
| gateway-drift-preflight | ✅ success |
| gateway-health-honest | ✅ success |
| tunnel-lifecycle |
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
E2E Target Results —
|
| Job | Result |
|---|---|
| cloud-onboard | ✅ success |
| concurrent-gateway-ports | |
| double-onboard | |
| full-e2e | ✅ success |
| gateway-drift-preflight | ✅ success |
| gateway-health-honest | ✅ success |
| tunnel-lifecycle | ✅ success |
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
E2E Target Results — ✅ All requested jobs passedRun: 28685614903
|
ericksoa
left a comment
There was a problem hiding this comment.
Approved at exact head 7281e94.
Verified 7/7 exact-head E2E scenarios, 41 passing PR checks with no failures or pending checks, 29/29 verified commits, zero unresolved review threads, and a clean conflict/overlap audit against current main.
Maintainer rationale for the non-binding Nemotron findings: the single 2-second-capped child bind probe is required by the synchronous stop API because Node reports in-process bind success/failure asynchronously; it runs once only after listener scans clear and fails closed. The global atomic onboard lock is port-independent, is held across gateway creation, and is proven across processes; the post-reap bind gate separately covers non-participating processes.
<!-- markdownlint-disable MD041 --> ## Summary This PR prepares the user-facing documentation for v0.0.74 before the release plan is frozen. It expands the release notes across the 56-commit train and closes durable documentation gaps found during the pre-tag commit scan. ## Changes - Expand the `v0.0.74` release notes to cover OpenShell 0.0.72, managed MCP, progressive tool disclosure, LangChain Deep Agents Code, onboarding, local inference, messaging, recovery, and contributor workflows. - Correct the `destroy` contract for retained per-name volumes, gateway-unreachable `--force` cleanup, managed MCP ownership, and same-name recovery. - Document separate remediation for an unreachable container DNS resolver versus one that answers with `NXDOMAIN` or `REFUSED`. - Document the Windows on Arm N1X automatic Ollama safeguard and its remaining large-model limitations. - State that messaging conflicts abort rebuild before backup or deletion, leaving the original sandbox intact. - Link the agent-runnable value benchmark from the contributor task index. - Synchronize generated agent command variants. - Validate with `npm run docs:sync-agent-variants` and `npm run docs`; Fern completed with 0 errors and 2 existing warnings. - Source summary: - [#6020](#6020) and [#5876](#5876) -> `docs/about/release-notes.mdx`: Consolidate the OpenShell 0.0.72 policy boundary and managed MCP lifecycle. - [#6251](#6251) and [#5989](#5989) -> `docs/about/release-notes.mdx`: Summarize progressive tool disclosure and sandbox-first inference controls. - [#6232](#6232), [#6082](#6082), [#6219](#6219), [#6214](#6214), [#6215](#6215), [#6230](#6230), and [#6260](#6260) -> `docs/about/release-notes.mdx`: Summarize the experimental LangChain Deep Agents Code status, secret, version, rebuild, snapshot, and MCP boundaries. - [#6166](#6166), [#6254](#6254), [#6265](#6265), [#6164](#6164), and [#6017](#6017) -> `docs/about/release-notes.mdx`: Summarize BuildKit prebuild, validated image reuse, bounded readiness, and preflight improvements. - [#6150](#6150) -> `docs/about/release-notes.mdx` and `docs/reference/troubleshooting.mdx`: Separate unreachable-resolver remediation from reachable-but-rejected DNS responses. - [#6234](#6234) -> `docs/about/release-notes.mdx`, `docs/inference/use-local-inference.mdx`, and `docs/get-started/windows-preparation.mdx`: Document N1X automatic 9B selection and the remaining explicit-large-model boundary. - [#6129](#6129), [#5987](#5987), [#5955](#5955), and [#6220](#6220) -> `docs/about/release-notes.mdx`, `docs/manage-sandboxes/messaging-channels.mdx`, `docs/reference/commands.mdx`, and `docs/reference/commands-nemohermes.mdx`: Document messaging policy persistence, status, and the pre-destructive conflict check. - [#5963](#5963), [#6050](#6050), [#6094](#6094), [#6238](#6238), [#5988](#5988), [#6235](#6235), [#6181](#6181), and [#5986](#5986) -> `docs/about/release-notes.mdx`, `docs/reference/commands.mdx`, and `docs/reference/commands-nemohermes.mdx`: Summarize day-two recovery and clarify retained-volume and local-only destroy semantics. - [#6200](#6200), [#6248](#6248), [#6168](#6168), [#6270](#6270), and [#5649](#5649) -> `docs/about/release-notes.mdx` and `CONTRIBUTING.md`: Summarize contributor setup and verification improvements and expose the advisory value benchmark. ## 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 <!-- Check exactly one tests line and one docs line. Check other lines when applicable. Add every requested justification or approval reference. --> - [ ] Tests added or updated for changed behavior - [ ] Existing tests cover changed behavior — justification: - [x] Tests not applicable — justification: documentation-only release preparation; generated-variant synchronization and the Fern docs build validate the changed pages 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 <!-- 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 or justification: tests are not applicable to this documentation-only change; `npm run docs` validates the source and generated routes. - [ ] Applicable broad gate passed — `npm test` for broad runtime/test-harness changes; `npm run check` for repo-wide validation/coverage changes — command/result: - [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) - [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) --- <!-- 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: Aaron Erickson <aerickson@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Expanded setup guidance for Windows on Arm devices with safer default local model selection. * Clarified local inference and sandbox messaging behavior, including conflict checks before rebuilds and safer recovery steps. * Updated destroy/rebuild/reference docs with more detailed warnings, failure handling, and volume-retention guidance. * Improved troubleshooting instructions for Docker DNS issues with clearer paths for unreachable vs. blocked resolvers. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
…DIA#5988) Release the managed host gateway port for the selected sandbox without disrupting registered peers that share the gateway. Make listener discovery, release confirmation, and replacement cutover fail closed, and cover the lifecycle with exact-head unit, integration, macOS, and live E2E validation. Fixes NVIDIA#5968 Signed-off-by: Yimo Jiang <yimoj@nvidia.com> Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
<!-- markdownlint-disable MD041 --> ## Summary This PR prepares the user-facing documentation for v0.0.74 before the release plan is frozen. It expands the release notes across the 56-commit train and closes durable documentation gaps found during the pre-tag commit scan. ## Changes - Expand the `v0.0.74` release notes to cover OpenShell 0.0.72, managed MCP, progressive tool disclosure, LangChain Deep Agents Code, onboarding, local inference, messaging, recovery, and contributor workflows. - Correct the `destroy` contract for retained per-name volumes, gateway-unreachable `--force` cleanup, managed MCP ownership, and same-name recovery. - Document separate remediation for an unreachable container DNS resolver versus one that answers with `NXDOMAIN` or `REFUSED`. - Document the Windows on Arm N1X automatic Ollama safeguard and its remaining large-model limitations. - State that messaging conflicts abort rebuild before backup or deletion, leaving the original sandbox intact. - Link the agent-runnable value benchmark from the contributor task index. - Synchronize generated agent command variants. - Validate with `npm run docs:sync-agent-variants` and `npm run docs`; Fern completed with 0 errors and 2 existing warnings. - Source summary: - [NVIDIA#6020](NVIDIA#6020) and [NVIDIA#5876](NVIDIA#5876) -> `docs/about/release-notes.mdx`: Consolidate the OpenShell 0.0.72 policy boundary and managed MCP lifecycle. - [NVIDIA#6251](NVIDIA#6251) and [NVIDIA#5989](NVIDIA#5989) -> `docs/about/release-notes.mdx`: Summarize progressive tool disclosure and sandbox-first inference controls. - [NVIDIA#6232](NVIDIA#6232), [NVIDIA#6082](NVIDIA#6082), [NVIDIA#6219](NVIDIA#6219), [NVIDIA#6214](NVIDIA#6214), [NVIDIA#6215](NVIDIA#6215), [NVIDIA#6230](NVIDIA#6230), and [NVIDIA#6260](NVIDIA#6260) -> `docs/about/release-notes.mdx`: Summarize the experimental LangChain Deep Agents Code status, secret, version, rebuild, snapshot, and MCP boundaries. - [NVIDIA#6166](NVIDIA#6166), [NVIDIA#6254](NVIDIA#6254), [NVIDIA#6265](NVIDIA#6265), [NVIDIA#6164](NVIDIA#6164), and [NVIDIA#6017](NVIDIA#6017) -> `docs/about/release-notes.mdx`: Summarize BuildKit prebuild, validated image reuse, bounded readiness, and preflight improvements. - [NVIDIA#6150](NVIDIA#6150) -> `docs/about/release-notes.mdx` and `docs/reference/troubleshooting.mdx`: Separate unreachable-resolver remediation from reachable-but-rejected DNS responses. - [NVIDIA#6234](NVIDIA#6234) -> `docs/about/release-notes.mdx`, `docs/inference/use-local-inference.mdx`, and `docs/get-started/windows-preparation.mdx`: Document N1X automatic 9B selection and the remaining explicit-large-model boundary. - [NVIDIA#6129](NVIDIA#6129), [NVIDIA#5987](NVIDIA#5987), [NVIDIA#5955](NVIDIA#5955), and [NVIDIA#6220](NVIDIA#6220) -> `docs/about/release-notes.mdx`, `docs/manage-sandboxes/messaging-channels.mdx`, `docs/reference/commands.mdx`, and `docs/reference/commands-nemohermes.mdx`: Document messaging policy persistence, status, and the pre-destructive conflict check. - [NVIDIA#5963](NVIDIA#5963), [NVIDIA#6050](NVIDIA#6050), [NVIDIA#6094](NVIDIA#6094), [NVIDIA#6238](NVIDIA#6238), [NVIDIA#5988](NVIDIA#5988), [NVIDIA#6235](NVIDIA#6235), [NVIDIA#6181](NVIDIA#6181), and [NVIDIA#5986](NVIDIA#5986) -> `docs/about/release-notes.mdx`, `docs/reference/commands.mdx`, and `docs/reference/commands-nemohermes.mdx`: Summarize day-two recovery and clarify retained-volume and local-only destroy semantics. - [NVIDIA#6200](NVIDIA#6200), [NVIDIA#6248](NVIDIA#6248), [NVIDIA#6168](NVIDIA#6168), [NVIDIA#6270](NVIDIA#6270), and [NVIDIA#5649](NVIDIA#5649) -> `docs/about/release-notes.mdx` and `CONTRIBUTING.md`: Summarize contributor setup and verification improvements and expose the advisory value benchmark. ## 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 <!-- Check exactly one tests line and one docs line. Check other lines when applicable. Add every requested justification or approval reference. --> - [ ] Tests added or updated for changed behavior - [ ] Existing tests cover changed behavior — justification: - [x] Tests not applicable — justification: documentation-only release preparation; generated-variant synchronization and the Fern docs build validate the changed pages 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 <!-- 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 or justification: tests are not applicable to this documentation-only change; `npm run docs` validates the source and generated routes. - [ ] Applicable broad gate passed — `npm test` for broad runtime/test-harness changes; `npm run check` for repo-wide validation/coverage changes — command/result: - [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) - [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) --- <!-- 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: Aaron Erickson <aerickson@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Expanded setup guidance for Windows on Arm devices with safer default local model selection. * Clarified local inference and sandbox messaging behavior, including conflict checks before rebuilds and safer recovery steps. * Updated destroy/rebuild/reference docs with more detailed warnings, failure handling, and volume-retention guidance. * Improved troubleshooting instructions for Docker DNS issues with clearer paths for unreachable vs. blocked resolvers. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Summary
Legacy
nemoclaw stopnow releases its managed host gateway port without disrupting another registered sandbox that shares the gateway. Canonicalnemoclaw tunnel stopremains tunnel-only and preserves the shared gateway. The onboard start/reuse path also enforces a single verified gateway listener before reuse or replacement, closing both symptoms in #5968 without breaking repeatable tunnel lifecycle.Related Issue
Fixes #5968
Changes
tunnel stop's documented tunnel-only contract while making the deprecatedstopcommand explicitly opt into gateway release; update command help and generated agent-variant docs.Module._loadchild harness, and add resolver, fail-closed, shared-ownership, command-boundary, cutover, real-process rebind, and tunnel-lifecycle coverage.onboard()holds the existing atomic cross-process filesystem lock (openSync(..., "wx")) through gateway reconciliation and launch, with a child-process regression proving a second CLI process is rejected; the strict post-reap bind check and OS bind exclusivity cover recovery commands and external processes outside that lock.net.Serverbind results asynchronously; poll authoritative listener state at most 20 times, then invoke the independent bind subprocess exactly once.Type of Change
Quality Gates
Verification
Verifiedin GitHubnpx prek run --from-ref main --to-ref HEADpassesnpm testpasses (broad runtime changes only)npm run docsbuilds without warnings (doc changes only)Additional exact-head local validation:
npm run build:cli,npm run typecheck,npm run lint, agent-variant docs sync, test-size/title/project/import checks, source-shape check, andscripts/generate-platform-docs.py --check.Signed-off-by: Yimo Jiang yimoj@nvidia.com