Skip to content

fix(messaging): warn/block second Slack Socket Mode sandbox on a shared gateway#5039

Merged
cv merged 1 commit into
NVIDIA:mainfrom
yimoj:fix/4953-slack-socket-mode-conflict
Jun 10, 2026
Merged

fix(messaging): warn/block second Slack Socket Mode sandbox on a shared gateway#5039
cv merged 1 commit into
NVIDIA:mainfrom
yimoj:fix/4953-slack-socket-mode-conflict

Conversation

@yimoj

@yimoj yimoj commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Slack Socket Mode is gateway-scoped, not only credential-scoped: even with two distinct Slack apps (different bot/app tokens), only one sandbox per OpenShell gateway reliably receives Socket Mode events. NemoClaw still reported the second sandbox's bridge as healthy, so the operator got a silent black hole. This adds a gateway-scoped conflict axis that warns/blocks (and marks status conflicted) when a second Slack sandbox is added to a gateway that already has one.

Related Issue

Fixes #4953

Changes

  • New conflict-detection/slack-socket-mode.ts with pure helpers (findSlackSocketModeGatewayConflicts, detectAllSlackSocketModeGatewayOverlaps, formatSlackSocketModeConflictMessage). A missing gatewayName normalizes to the default nemoclaw gateway so legacy entries compare correctly ([WSL2 x86_64][Sandbox] NEMOCLAW_GATEWAY_PORT=N onboard recreates global gateway and destroys previous sandbox — concurrent instances unsupported #4422). This axis is independent of the existing matching-token / unknown-token credential detection — it fires on a shared gateway regardless of whether the tokens differ.
  • Onboard: extracted both conflict axes into onboard/messaging-conflict-guard.ts (keeps onboard.ts net-negative for the codebase-growth guardrail) and refuse a second Slack sandbox on the same gateway in non-interactive mode / require override interactively.
  • channels add slack: warn/block on a shared gateway, honoring --force; the gateway lookup is fail-soft so a malformed registry cannot crash the add or bypass the existing guarded credential check.
  • status: mark a shared-gateway Slack pair as conflicted (slack-socket-mode-gateway) rather than silently healthy, deduped against the credential-overlap line.
  • Unit tests for the detection helpers, the onboard guard orchestration, the channels add paths (same-gateway block, different-gateway pass, fail-soft), and the status renderer.

Type of Change

  • Code change (feature, bug fix, or refactor)

Verification

  • npm test passes (CLI project; the only failures are pre-existing environment-driven subprocess-spawn timeouts and the e2e-fixture-context SIGKILL/SIGTERM timing test — all unrelated to these files, which pass in isolation)
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • codex review --uncommitted clean ("No correctness-impacting issues were found")

E2E (real CLI, isolated gateway port): onboarded a first Slack sandbox (sa-4953) on gateway nemoclaw-8085, then onboarded a second Slack sandbox on the same gateway. Before the fix it silently proceeded to build the second sandbox (the #4953 black hole); after the fix it aborts before sandbox creation with:

⚠ Slack Socket Mode is already enabled for sandbox 'sa-4953' on this gateway; only one sandbox can receive Slack Socket Mode events unless the gateway supports multiplexing.
Aborting: only one sandbox per gateway can receive Slack Socket Mode events. ...

Signed-off-by: Yimo Jiang yimoj@nvidia.com

Summary by CodeRabbit

  • New Features

    • Slack Socket Mode gateway conflict detection prevents multiple sandboxes from receiving Socket Mode events on the same gateway; status output now shows a Slack-specific overlap reason.
  • Behavior

    • Adding a sandbox now warns, prompts, blocks, or aborts based on gateway vs credential conflicts; verification failures log a warning and allow the add to continue.
  • Tests

    • Expanded tests for gateway vs credential conflicts, same/different gateways, interactive/non-interactive flows, and failure handling.
  • Refactor

    • Centralized messaging conflict enforcement during sandbox creation.

@coderabbitai

coderabbitai Bot commented Jun 9, 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

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: e2f4ae41-a306-4046-8c76-82e75e2bc6f8

📥 Commits

Reviewing files that changed from the base of the PR and between 6f2b837 and 39b0b0a.

📒 Files selected for processing (12)
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/inventory/index.test.ts
  • src/lib/inventory/index.ts
  • src/lib/messaging/applier/conflict-detection-slack-gateway.test.ts
  • src/lib/messaging/applier/conflict-detection/index.ts
  • src/lib/messaging/applier/conflict-detection/slack-socket-mode.ts
  • src/lib/messaging/applier/conflict-detection/types.ts
  • src/lib/onboard.ts
  • src/lib/onboard/messaging-conflict-guard.test.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • src/lib/status-command-deps.ts
✅ Files skipped from review due to trivial changes (1)
  • src/lib/messaging/applier/conflict-detection/index.ts
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/lib/messaging/applier/conflict-detection/types.ts
  • src/lib/inventory/index.test.ts
  • src/lib/onboard/messaging-conflict-guard.test.ts
  • src/lib/inventory/index.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • src/lib/messaging/applier/conflict-detection/slack-socket-mode.ts
  • src/lib/onboard.ts
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts

📝 Walkthrough

Walkthrough

Adds gateway-scoped Slack Socket Mode conflict detection, status reporting and overlap merging, a Slack-only add-channel precheck, and an onboarding guard that enforces or prompts on gateway-level Slack conflicts, with tests covering detection, messaging, and control-flow behaviors.

Changes

Slack Socket Mode Gateway-Scoped Conflict Detection and Enforcement

Layer / File(s) Summary
Slack gateway conflict detection foundation
src/lib/messaging/applier/conflict-detection/types.ts, src/lib/messaging/applier/conflict-detection/slack-socket-mode.ts, src/lib/messaging/applier/conflict-detection-slack-gateway.test.ts, src/lib/messaging/applier/conflict-detection/index.ts
ConflictRegistryEntry gains optional gatewayName. New helpers/detectors: resolveEntryGatewayName, entryHasActiveSlack, findSlackSocketModeGatewayConflicts(), detectAllSlackSocketModeGatewayOverlaps(), and formatSlackSocketModeConflictMessage(). Tests cover detection rules, overlaps grouping, and message formatting.
Status and overlap merging
src/lib/inventory/index.ts, src/lib/inventory/index.test.ts, src/lib/status-command-deps.ts
MessagingOverlap.reason extended with "slack-socket-mode-gateway". showStatusCommand special-cases Slack gateway overlaps. backfillAndFindOverlaps now computes gateway-scoped Slack overlaps and returns them as normalized channel: "slack" entries with reason: "slack-socket-mode-gateway".
Add-channel action enforcement
src/lib/actions/sandbox/policy-channel.ts, src/lib/actions/sandbox/policy-channel-conflict.test.ts
Adds checkSlackSocketModeGatewayConflict() and calls it after credential checks in addSandboxChannel(); conflicts allow --force, abort in non-interactive mode, or prompt interactively. Tests assert same-gateway blocking, credential-precedence, different-gateway pass-through, and fail-soft behavior.
Sandbox creation messaging conflict guard
src/lib/onboard/messaging-conflict-guard.ts, src/lib/onboard/messaging-conflict-guard.test.ts, src/lib/onboard.ts
New enforceMessagingChannelConflicts(deps) runs credential-scoped and Slack gateway-scoped checks during createSandbox, merges disabled-channel state, centralizes abort/prompt behavior (injectable exit), and is integrated into createSandbox. Tests cover interactive/non-interactive aborts, prompts, acceptances, and noop conditions.

Sequence Diagram(s)

sequenceDiagram
  participant User as User/Operator
  participant Onboard as Onboard Flow
  participant Guard as enforceMessagingChannelConflicts
  participant Registry as Sandbox Registry
  participant Detection as findSlackSocketModeGatewayConflicts / detectAllSlackSocketModeGatewayOverlaps
  participant Prompt as promptContinue

  User->>Onboard: Create sandbox with Slack
  Onboard->>Guard: enforceMessagingChannelConflicts(deps)
  Guard->>Registry: listSandboxes / backfill
  Registry-->>Guard: [existing sandboxes]
  Guard->>Detection: detect gateway conflicts/overlaps
  Detection-->>Guard: [{sandbox: "other", gatewayName: "shared-gateway"}]
  Guard->>Guard: Log Slack conflict warning via formatSlackSocketModeConflictMessage
  alt Non-interactive
    Guard->>Onboard: Abort (exit)
  else Interactive
    Guard->>Prompt: "Continue anyway?" prompt
    alt User declines
      Prompt-->>Guard: false
      Guard->>Onboard: Abort (throw)
    else User accepts
      Prompt-->>Guard: true
      Guard->>Onboard: Resolve (allow creation)
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#4945: Refactors messaging conflict/overlap machinery to be plan-based, which this change builds upon to add Slack Socket Mode gateway conflict detection and status reporting.

Poem

"I hopped along the gateway trail,
two bots, one socket — a single tale.
Now checks and tests keep events in line,
only one listener per gateway — that's fine.
🥕 — a rabbit with a happy spine."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 68.75% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(messaging): warn/block second Slack Socket Mode sandbox on a shared gateway' directly aligns with the main changeset objective of detecting and blocking/warning when a second Slack Socket Mode sandbox is added to the same gateway.
Linked Issues check ✅ Passed The PR fully addresses issue #4953's requirements: detects Slack Socket Mode gateway conflicts, prevents silent failures by warning/blocking a second sandbox on the same gateway during onboard and channels add, surfaces conflicts in status output, treats stopped channels as non-consumers, and provides clear operator-facing messaging.
Out of Scope Changes check ✅ Passed All changes are directly scoped to addressing issue #4953: new gateway-conflict detection in slack-socket-mode.ts, integration into onboarding via messaging-conflict-guard.ts, channels add precheck in policy-channel.ts, status reporting in index.ts, and supporting tests. No unrelated refactoring or scope creep detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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 `@src/lib/onboard.ts`:
- Around line 2778-2793: enforceMessagingChannelConflicts is being run against
the full configured channel set before resolveDisabledChannels/disabledEnvKeys
pruning, causing sandboxes with channels marked disabled (e.g., slack stopped)
to falsely block others; update the call site to compute the effective channel
set (run resolveDisabledChannels and/or inspect disabledEnvKeys) and pass that
post-pruning state into enforceMessagingChannelConflicts (or alternatively move
the enforceMessagingChannelConflicts invocation to after resolveDisabledChannels
returns) so Socket Mode conflict checks use the pruned channel list; update the
argument signature or add a new parameter (e.g., disabledChannels or
effectiveChannels) to enforceMessagingChannelConflicts and adjust callers
accordingly (symbols: enforceMessagingChannelConflicts, resolveDisabledChannels,
disabledEnvKeys).
🪄 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: 413743a7-2543-4d1a-a58f-fd86f20f1c75

📥 Commits

Reviewing files that changed from the base of the PR and between 784f573 and 02d14fc.

📒 Files selected for processing (12)
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/inventory/index.test.ts
  • src/lib/inventory/index.ts
  • src/lib/messaging/applier/conflict-detection-slack-gateway.test.ts
  • src/lib/messaging/applier/conflict-detection/index.ts
  • src/lib/messaging/applier/conflict-detection/slack-socket-mode.ts
  • src/lib/messaging/applier/conflict-detection/types.ts
  • src/lib/onboard.ts
  • src/lib/onboard/messaging-conflict-guard.test.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • src/lib/status-command-deps.ts

Comment thread src/lib/onboard.ts
@yimoj

yimoj commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @coderabbitai — fixed in f2d86c1. The current sandbox's stopped channels (channels stop) are now folded into the effective plan's disabledChannels before conflict detection, so a stopped Slack bridge counts as neither a credential consumer nor a Socket Mode consumer and no longer falsely blocks another sandbox on the same gateway. Applied to both the credential and gateway axes (both honor plan.disabledChannels), with a regression test in messaging-conflict-guard.test.ts.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@yimoj: Great fix — folding disabledChannels in before both axes is exactly the right approach. A sandbox that has stopped its Slack bridge should be invisible to conflict detection on both the credential and gateway dimensions, and tying it to the effective plan ensures future callers automatically get the same behaviour without any extra ceremony. The regression test in messaging-conflict-guard.test.ts seals it nicely. Thanks for the thorough follow-through!

🐇✨


✏️ Learnings added
Learnt from: yimoj
URL: https://github.com/NVIDIA/NemoClaw/pull/5039

Timestamp: 2026-06-09T11:20:46.835Z
Learning: In the NemoClaw codebase, when running messaging-channel conflict detection (both credential-hash axis and gateway-scoped Slack Socket Mode axis) during sandbox onboard or `channels add`, stopped channels (those halted via `channels stop`) must first be folded into the effective plan's `disabledChannels` before invoking `findChannelConflictsFromPlan` or `findSlackSocketModeGatewayConflicts`. This prevents a sandbox whose Slack bridge has been stopped from being counted as an active credential consumer or Socket Mode consumer, avoiding false-positive conflict blocks. The fix was landed in commit f2d86c169 and is covered by a regression test in src/lib/onboard/messaging-conflict-guard.test.ts.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@wscurran wscurran added area: messaging Messaging channels, bridges, manifests, or channel lifecycle bug-fix PR fixes a bug or regression integration: slack Slack integration or channel behavior labels Jun 9, 2026
@yimoj yimoj force-pushed the fix/4953-slack-socket-mode-conflict branch from f2d86c1 to 4faff18 Compare June 10, 2026 02:37
Comment thread src/lib/actions/sandbox/policy-channel.ts Fixed
@yimoj yimoj added the v0.0.63 Release target label Jun 10, 2026
@yimoj

yimoj commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review — rebased onto current main (conflict resolved) and addressed the credential-vs-gateway ordering: status now reports both conflict axes independently, and channels add runs the credential check before the gateway check so a shared Slack token surfaces the gateway-independent warning first. Latest head 07627c7.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

@yimoj: On it! Kicking off a fresh review of the rebased branch with the credential-vs-gateway ordering fix included.

✅ Action performed

Full review finished.

@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.

♻️ Duplicate comments (1)
src/lib/actions/sandbox/policy-channel.ts (1)

494-494: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove the unused fallback initializer.

The initial value (s) => s assigned to formatSlackSocketModeConflictMessage is never used because the variable is always overwritten at line 497 inside the try block. If the try block throws, the function returns early at line 509, so the fallback is unreachable. Remove the initializer and declare the variable with type annotation only.

🧹 Proposed fix
-  let formatSlackSocketModeConflictMessage: (s: string) => string = (s) => s;
+  let formatSlackSocketModeConflictMessage: (s: string) => string;
🤖 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/policy-channel.ts` at line 494, The variable
formatSlackSocketModeConflictMessage currently has an unused fallback
initializer "(s) => s"; remove that initializer and declare it with only its
type annotation (e.g., let formatSlackSocketModeConflictMessage: (s: string) =>
string;) so the value is assigned exclusively inside the try block where it's
actually set and the unreachable fallback is eliminated.

Source: Linters/SAST tools

🤖 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.

Duplicate comments:
In `@src/lib/actions/sandbox/policy-channel.ts`:
- Line 494: The variable formatSlackSocketModeConflictMessage currently has an
unused fallback initializer "(s) => s"; remove that initializer and declare it
with only its type annotation (e.g., let formatSlackSocketModeConflictMessage:
(s: string) => string;) so the value is assigned exclusively inside the try
block where it's actually set and the unreachable fallback is eliminated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 64ead58a-796d-493b-9d87-a8ba42b8fdd8

📥 Commits

Reviewing files that changed from the base of the PR and between fc3c0a9 and 07627c7.

📒 Files selected for processing (12)
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/inventory/index.test.ts
  • src/lib/inventory/index.ts
  • src/lib/messaging/applier/conflict-detection-slack-gateway.test.ts
  • src/lib/messaging/applier/conflict-detection/index.ts
  • src/lib/messaging/applier/conflict-detection/slack-socket-mode.ts
  • src/lib/messaging/applier/conflict-detection/types.ts
  • src/lib/onboard.ts
  • src/lib/onboard/messaging-conflict-guard.test.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • src/lib/status-command-deps.ts

@yimoj

yimoj commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @coderabbitai — addressed in 6f2b837. Dropped the unreachable (s) => s fallback by building the conflict messages inside the try block where the applier module is in scope.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@yimoj: That's the cleaner approach — keeping the message construction inside the try block eliminates the dead fallback and makes the applier module's scope explicit. Thanks for the follow-up!

🐇✨

@yimoj

yimoj commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor
✅ 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.

…ed gateway

Slack Socket Mode is gateway-scoped, not only credential-scoped: even with two
distinct Slack apps (different bot/app tokens), only one sandbox per OpenShell
gateway reliably receives Socket Mode events. NemoClaw still reported the second
sandbox's bridge as healthy, so the operator got a silent black hole (NVIDIA#4953).

The existing detection only catches a *shared* token (matching-token /
unknown-token). Add a complementary gateway-scoped axis, keyed on the sandbox's
OpenShell gateway registration name, that fires whenever another sandbox on the
same gateway already has Slack active — regardless of whether the tokens differ:

- New conflict-detection/slack-socket-mode.ts with pure detection helpers
  (findSlackSocketModeGatewayConflicts, detectAllSlackSocketModeGatewayOverlaps)
  and the operator-facing message. A missing gatewayName normalizes to the
  default `nemoclaw` gateway so legacy entries compare correctly (NVIDIA#4422).
- Onboard: extract both conflict axes into onboard/messaging-conflict-guard.ts
  (keeps onboard.ts net-negative for the growth guardrail) and refuse a second
  Slack sandbox on the same gateway unless overridden. Stopped channels
  (`channels stop`) are folded into the effective plan's disabledChannels before
  both axes so a stopped bridge is not counted as a consumer.
- `channels add slack`: run the credential check first (gateway-independent and
  more actionable), then a fail-soft gateway-scoped check for the distinct-token,
  same-gateway case; honors --force.
- `status`: report credential and gateway overlaps independently so a pair that
  shares both a token and a gateway still surfaces the cross-gateway credential
  warning; mark a shared-gateway Slack pair conflicted instead of healthy.

E2E: onboarded a first Slack sandbox, then a second on the same gateway — before
the fix it silently proceeded to build; after the fix it aborts with the Socket
Mode conflict message before creating the sandbox.

Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
@yimoj yimoj force-pushed the fix/4953-slack-socket-mode-conflict branch from 6f2b837 to 39b0b0a Compare June 10, 2026 07:13
@yimoj

yimoj commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review — rebased onto current main (resolved conflicts from the #4945 revert / #5115), and addressed the channel-add gateway-resolution finding: the Slack conflict check now compares against the default nemoclaw gateway that channels add actually registers the provider on (via recoverNamedGatewayRuntime), matching the mutation path. Latest head 39b0b0a.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

@yimoj: On it — kicking off a fresh review of the rebased branch with the recoverNamedGatewayRuntime-aligned gateway-resolution fix included. 🐇

✅ 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.

@prekshivyas prekshivyas self-assigned this Jun 10, 2026

@prekshivyas prekshivyas 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.

Reviewed (code + security checklist). Adds a gateway-scoped Slack Socket Mode conflict axis (independent of the existing credential-token axis) so a second Slack sandbox on the same OpenShell gateway is warned/blocked at onboard and channels add, and flagged as conflicted in status, instead of becoming a silent black hole (#4953).

Approve. Verified the load-bearing wiring against source: policy-channel.ts hardcoding BASE_GATEWAY_NAME for the add path is correct (recoverNamedGatewayRuntime always selects nemoclaw), while onboard uses the per-port GATEWAY_NAME — no false negative; gatewayName is a real persisted field with legacy→nemoclaw normalization; the credential axis runs first and short-circuits the shared-token case to the more-actionable warning. Conflict messages interpolate only sandbox names, never tokens (tests assert tokens absent). Security: all categories pass.

Non-blocking nits:

  • PR body says the status Slack line is "deduped against the credential-overlap line," but the code intentionally does not dedup (concatenates both axes, with an explaining comment). Code is fine — correct the body wording.
  • detectAllSlackSocketModeGatewayOverlaps emits all N-choose-2 pairs, so 3+ Slack sandboxes on one gateway produce O(N²) status lines. N is realistically tiny; optionally collapse to one line per gateway.

Tests thorough: pure-helper cases (same/different/missing gateway, disabled Slack, self-exclusion, N-pair enumeration), onboard-guard orchestration, channels add paths incl. credential-first ordering and fail-soft, and the status renderer.

@cv cv merged commit 4d3b479 into NVIDIA:main Jun 10, 2026
33 checks passed
miyoungc added a commit that referenced this pull request Jun 11, 2026
## Summary
- Add the v0.0.63 release-note section using the published development
note as source context.
- Update source docs for sandbox recovery, OpenClaw config restore
safety, managed vLLM selection, Slack Socket Mode conflict handling, and
host diagnostics.
- Refresh generated `nemoclaw-user-*` skills from the updated Fern MDX
docs.
- Update the release-doc refresh skill so post-release docs for version
`n` look up the matching announcement discussion and use the `n+1` patch
release label.
- Fix CLI/docs parity by avoiding a `--from <Dockerfile>` flag mention
inside the `upgrade-sandboxes` command section.

## Source summary
- #5034 -> `docs/reference/troubleshooting.mdx`,
`docs/about/release-notes.mdx`: Document safer stale-sandbox recovery
through `rebuild --yes` before recreating from scratch.
- #5091 -> `docs/reference/troubleshooting.mdx`,
`docs/about/release-notes.mdx`: Document Docker-driver post-reboot
recovery from OpenShell container labels.
- #5101, #5174, #5177 -> `docs/manage-sandboxes/backup-restore.mdx`,
`docs/about/release-notes.mdx`: Document OpenClaw `openclaw.json`
preservation, merge behavior, and fail-safe restore handling.
- #5102 -> `docs/reference/commands.mdx`,
`docs/reference/commands-nemohermes.mdx`,
`docs/manage-sandboxes/lifecycle.mdx`, `docs/about/release-notes.mdx`:
Document `upgrade-sandboxes` image-fingerprint drift detection.
- #4201 -> `docs/reference/troubleshooting.mdx`,
`docs/about/release-notes.mdx`: Document the installer diagnostic for
unexpected Docker daemon access outside the `docker` group.
- #5038 -> `docs/inference/inference-options.mdx`,
`docs/inference/use-local-inference.mdx`,
`docs/about/release-notes.mdx`: Document the interactive managed-vLLM
model picker and non-interactive override behavior.
- #5040, #5041 -> `docs/reference/troubleshooting.mdx`,
`docs/about/release-notes.mdx`: Document Ollama auth-proxy recovery and
host DNS preflight diagnostics.
- #4986, #5039 -> `docs/manage-sandboxes/messaging-channels.mdx`,
`docs/about/release-notes.mdx`: Document Slack validation and duplicate
Slack Socket Mode sandbox handling.
- #4981, #5168 -> `docs/about/release-notes.mdx`: Capture Hermes gateway
secret-guard and wrapped-argv startup hardening in the release surface.
- Follow-up ->
`.agents/skills/nemoclaw-contributor-update-docs/SKILL.md`: Record the
post-release docs workflow, discussion-announcement lookup, and
next-patch release label rule.
- Follow-up -> `docs/reference/commands.mdx`,
`docs/reference/commands-nemohermes.mdx`: Reword custom Dockerfile
sandbox text so CLI parity does not treat `--from` as an
`upgrade-sandboxes` flag.

## Verification
- `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix
nemoclaw-user --doc-platform fern-mdx`
- `npm run docs`
- `npm run build:cli`
- `bash test/e2e/e2e-cloud-experimental/check-docs.sh --only-cli`
- Skip-term scan for `docs/.docs-skip` blocked terms across generated
user skills

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

## Summary by CodeRabbit

* **Documentation**
* Enhanced local inference setup with interactive model selection
prompts and environment variable overrides
* Improved sandbox upgrade detection using build fingerprints and
version checks
* Clarified configuration restore behavior preserving user settings
during rebuild/restore
  * Added gateway authentication as fifth security layer
  * Expanded Slack messaging validation with live credential checking
* Enhanced troubleshooting guidance for Docker access, DNS issues, and
sandbox recovery
* Updated release notes for v0.0.63 featuring sandbox recovery and
inference improvements

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: messaging Messaging channels, bridges, manifests, or channel lifecycle bug-fix PR fixes a bug or regression integration: slack Slack integration or channel behavior v0.0.63 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Linux][Agent&Skills] Second sandbox Slack bridge silently fails — Socket Mode events routed only to first registered sandbox on shared gateway

5 participants