Skip to content

fix(messaging): add WhatsApp channel diagnostics (#4386)#4406

Merged
cv merged 5 commits into
NVIDIA:mainfrom
yimoj:fix/4386-whatsapp-inbound-diagnostics
May 29, 2026
Merged

fix(messaging): add WhatsApp channel diagnostics (#4386)#4406
cv merged 5 commits into
NVIDIA:mainfrom
yimoj:fix/4386-whatsapp-inbound-diagnostics

Conversation

@yimoj
Copy link
Copy Markdown
Contributor

@yimoj yimoj commented May 28, 2026

Summary

Adds nemoclaw <sandbox> channels status [--channel <name>] [--json], a bounded host-side diagnostic that surfaces QR/session state, Noise WebSocket state, inbound event delivery, policy coverage, and channel registration as separate signals so a paired-but-idle WhatsApp channel cannot be silently treated as healthy.

Related Issue

Fixes #4386

Changes

  • New nemoclaw <sandbox> channels status command (src/commands/sandbox/channels/status.ts).
  • New WhatsApp diagnostic core (src/lib/sandbox/whatsapp-diagnostics.ts) — pure parsing and verdict logic with sanitized timestamp, connection-state, and error-category outputs.
  • New orchestrator (src/lib/actions/sandbox/channel-status.ts) — bounded openshell sandbox exec probe (8s) with shell that filters the probe shell out of its own pgrep, supports both OpenClaw (/sandbox/.openclaw/whatsapp) and Hermes (/sandbox/.hermes/platforms/whatsapp/session) state layouts, and routes paused channels through the basic per-channel report instead of probing a torn-down bridge.
  • Verdict short-circuits to idle when paired + WebSocket up + no inbound observed (the [Brev][Agent&UX] WhatsApp inbound messages not received despite active Noise protocol WebSocket and successful pairing #4386 shape), and refuses to declare healthy when any fail signal is present.
  • Sanitizers reject non-timestamp lastInboundAt values, collapse non-whitelisted connection states to other, redact heartbeat note/lastError to a category vocabulary (unauthorized, connection-closed, rate-limited, logged-out, qr-expired, other), and replace Node's JSON.parse error message with a fixed string so the host-side JSON output never echoes raw sandbox-owned heartbeat contents.
  • sandbox doctor's Messaging check no longer reports ok when WhatsApp is enabled (it points to the new diagnostic instead).
  • WhatsApp channels add and onboarding QR branches now surface setupNotes, including a hint to run channels status after pairing.
  • 35 new hermetic unit tests cover paired-healthy, paired-idle, unpaired, parse-error, policy/config gaps, paused channels, sanitization, embedded-bridge pgrep edge case, and a sh -n regression guard for the probe script.

Type of Change

  • Code change with doc updates

Verification

  • Focused suites pass: npx vitest run src/lib/sandbox/whatsapp-diagnostics.test.ts src/lib/actions/sandbox/channel-status.test.ts ... (352/352 across related suites).
  • npm run build:cli and npm run typecheck:cli clean.
  • bash test/e2e/e2e-cloud-experimental/check-docs.sh --only-cli passes (new command documented in docs/reference/commands.mdx).
  • Six rounds of codex review -c sandbox_mode="danger-full-access" --uncommitted until no actionable findings.
  • Hermetic E2E repro on a uniquely named sandbox (wa-diag-4386-*): pre-fix channels status did not exist and doctor reported WhatsApp [ok]; post-fix channels status reports separate signals with a non-zero exit and doctor surfaces a pointer to the new command. Live WhatsApp QR pairing was not possible in the triage environment (reported in the issue analysis), so inbound-delivery healthy/idle paths are covered by hermetic fixtures.
  • No secrets, API keys, or credentials committed.

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

Summary by CodeRabbit

  • New Features

    • Added a sandbox channels status command to run per-channel runtime diagnostics (supports --channel and --json; non-zero exit for unhealthy/verdicts).
  • Documentation

    • New command docs, example usage, and WhatsApp-specific diagnostic guidance; onboarding and post-pairing notes now recommend running the status check.
  • Tests

    • Extensive tests covering WhatsApp diagnostics, probe behaviors, verdicts, and CLI output modes.
  • Bug Fixes

    • Messaging doctor now surfaces WhatsApp-specific guidance to run the status probe.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

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: 11f76180-7cf5-4449-b481-45a24db676e6

📥 Commits

Reviewing files that changed from the base of the PR and between 75da1e6 and 72c3cdf.

📒 Files selected for processing (2)
  • src/commands/sandbox/channels/status.ts
  • src/lib/actions/sandbox/channel-status.ts
💤 Files with no reviewable changes (1)
  • src/lib/actions/sandbox/channel-status.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/commands/sandbox/channels/status.ts

📝 Walkthrough

Walkthrough

Adds a sandbox channel status action and oclif command that probes messaging channels (WhatsApp-specialized), parses heartbeat/log/process evidence into signals, selects a verdict (healthy/idle/unpaired/config_gap/policy_gap/probe_failed), and renders JSON or human text; includes tests, doctor/onboard UX changes, and docs.

Changes

WhatsApp Channel Status Diagnostics

Layer / File(s) Summary
WhatsApp diagnostic types and signal extraction
src/lib/sandbox/whatsapp-diagnostics.ts
Diagnostic severity/signal/verdict/heartbeat/probe types; per-signal extractors (pairing, Noise WebSocket, inbound delivery, policy/registration, process); heartbeat parsing/sanitization; log keyword summarization.
WhatsApp diagnostic test coverage
src/lib/sandbox/whatsapp-diagnostics.test.ts
Tests for evaluateWhatsappDiagnostics, parseWhatsappHeartbeat, and summarizeWhatsappLogLines across verdicts, parsing edge-cases, Hermes hints, and log summarization.
Channel status action with probe orchestration
src/lib/actions/sandbox/channel-status.ts
showSandboxChannelStatus: resolve OpenClaw/Hermes state dirs, generate/exec in-sandbox probe script with begin/end markers, parse heartbeat/log/process sections, enrich with registry/preset metadata, evaluate diagnostics, render JSON/text, map verdict→exit code, and handle paused channels.
Channel status action test suite
src/lib/actions/sandbox/channel-status.test.ts
Tests for idle/healthy flows, probe failures (missing marker, exec timeout), config gaps, Hermes pairing hints, generated probe script syntax and pid-filtering, paused-channel behavior, and non-WhatsApp basic reports; uses dependency stubs and process.exit assertions.
CLI command and registration
src/commands/sandbox/channels/status.ts, src/lib/cli/command-registry.test.ts, src/lib/cli/public-display-defaults.ts
New sandbox:channels:status oclif command (enableJsonFlag, --channel) invoking showSandboxChannelStatus and setting non-zero exit for non-healthy/unknown JSON verdicts; test counts updated and public-display entry added.
Doctor checks, setup notes, and documentation
src/lib/actions/sandbox/doctor.ts, src/lib/actions/sandbox/policy-channel.ts, src/lib/onboard/messaging-channel-setup.ts, src/lib/sandbox/channels.ts, docs/reference/commands.mdx
Doctor returns info when WhatsApp enabled with hint to run channels status; WhatsApp setupNotes added and printed after QR pairing/onboarding; docs updated with command usage, flags, exit behavior, and probe bounds.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI as sandbox:channels:status
  participant Action as showSandboxChannelStatus
  participant Exec as ExecRunner
  participant Eval as evaluateWhatsappDiagnostics
  participant Render as renderReport
  
  User->>CLI: nemoclaw <sandbox> channels status --channel whatsapp
  CLI->>Action: invoke with {sandbox, channel, asJson, quietJson}
  Action->>Action: resolve WhatsApp state directories
  Action->>Exec: execute probe shell script (openshell sandbox exec)
  Exec-->>Action: stdout (heartbeat + logs + process state)
  Action->>Action: parseProbeOutput -> ProbeInput
  Action->>Eval: evaluateWhatsappDiagnostics(ProbeInput)
  Eval-->>Action: WhatsappDiagnosticReport {verdict, signals, hints}
  Action->>Render: renderReport(report, asJson)
  Render-->>Action: JSON or formatted text
  Action->>Action: exitCodeFor(verdict) → 0 or 1
  Action-->>CLI: report
  CLI-->>User: stdout + process.exitCode
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

enhancement: messaging, v0.0.54

Suggested reviewers

  • ericksoa
  • wscurran
  • cv

Poem

🐰 I hop through sandboxes, keen and spry,
I sniff the heartbeats logs imply,
I parse the noise and spot the drift,
I send a hint when bridges shift.
Run channels status — let health reply!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% 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): add WhatsApp channel diagnostics' is directly related to the changeset. The PR adds WhatsApp channel status diagnostics with the new CLI command 'nemoclaw channels status', diagnostic core, orchestrator, and supporting UX integrations.
Linked Issues check ✅ Passed The PR fully addresses all coding requirements from #4386: detects 'paired but no inbound' condition via separate signals (pairing state, WebSocket, inbound delivery, policy coverage, registration), sanitizes heartbeat fields with normalized error categories, provides a bounded host-side diagnostic via the new 'channels status' command, and integrates with doctor/onboarding UX.
Out of Scope Changes check ✅ Passed All changes are scoped to the PR objectives: new diagnostic command and support infrastructure, test coverage, documentation, and selective integrations with doctor check and onboarding setup notes. No unrelated changes detected outside the linked issue requirements.

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

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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

Comment thread src/commands/sandbox/channels/status.ts Fixed
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 `@docs/reference/commands.mdx`:
- Around line 766-768: Replace the fenced code block that currently uses
"console" and includes a "$" prompt for the command `nemoclaw my-assistant
channels status --channel whatsapp` with a copyable shell block: change the
fence language from "console" to "bash" (or "sh") and remove the leading "$" so
the block contains just the raw command `nemoclaw my-assistant channels status
--channel whatsapp`; ensure no prompt markers remain and the block is
runnable/copyable.
🪄 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: ad075eea-5800-4ac5-af15-33ecbb2d7264

📥 Commits

Reviewing files that changed from the base of the PR and between 78909ec and fbf06e8.

📒 Files selected for processing (12)
  • docs/reference/commands.mdx
  • src/commands/sandbox/channels/status.ts
  • src/lib/actions/sandbox/channel-status.test.ts
  • src/lib/actions/sandbox/channel-status.ts
  • src/lib/actions/sandbox/doctor.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/cli/command-registry.test.ts
  • src/lib/cli/public-display-defaults.ts
  • src/lib/onboard/messaging-channel-setup.ts
  • src/lib/sandbox/channels.ts
  • src/lib/sandbox/whatsapp-diagnostics.test.ts
  • src/lib/sandbox/whatsapp-diagnostics.ts

Comment thread docs/reference/commands.mdx Outdated
yimoj added a commit to yimoj/NemoClaw that referenced this pull request May 28, 2026
The added `bash`-style invocation in docs/reference/commands.mdx now
follows the project's documented convention — copyable command blocks
use a `bash` fence with no leading `$`. The rest of the file's legacy
`console` blocks are left untouched to keep this change scoped to the
new section CodeRabbit flagged on PR NVIDIA#4406.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
@yimoj yimoj added the v0.0.55 label May 28, 2026
yimoj and others added 3 commits May 28, 2026 17:01
Adds `nemoclaw <sandbox> channels status [--channel <name>] [--json]`,
a bounded host-side diagnostic that probes a sandbox's WhatsApp bridge
and reports QR/session state, Noise WebSocket state, inbound event
delivery, policy coverage, and channel registration as separate
signals. A paired channel with no observed inbound delivery now
returns verdict `idle` (exit 1) so the silent "paired but no inbound
events" failure mode from the issue cannot pass as healthy.

The doctor's Messaging check no longer reports `ok` when WhatsApp is
enabled — conflict-signature heuristics do not cover WhatsApp Web —
and instead points operators at the new diagnostic. The diagnostic
sanitizes timestamps, redacts heartbeat error/note fields to a fixed
category vocabulary, and whitelists connection-state strings so the
host-side JSON output cannot leak phone numbers, message bodies, or
tokens that bridges sometimes embed in their heartbeat files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
The added `bash`-style invocation in docs/reference/commands.mdx now
follows the project's documented convention — copyable command blocks
use a `bash` fence with no leading `$`. The rest of the file's legacy
`console` blocks are left untouched to keep this change scoped to the
new section CodeRabbit flagged on PR NVIDIA#4406.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
…cs (NVIDIA#4386)

Two follow-up hardenings on top of the rebased WhatsApp diagnostic:

- Strict ISO-8601 only for heartbeat timestamps. `Date.parse` accepts
  loose forms (bare integer, `Date.toString()` output with parenthesized
  text) that the diagnostic would otherwise echo back through
  `channels status --json` or use as inbound evidence. Reject anything
  that does not match the ISO 8601 shape and re-emit accepted values via
  `toISOString()` so the rendered detail is deterministic regardless of
  how the bridge serialized the timestamp.
- Explicit `PROC_DONE` marker after the in-sandbox pgrep so the orchestrator
  distinguishes "pgrep completed with no matches" (the bridge has crashed
  or runs under an unmatched name → fail) from "the probe aborted before
  reaching pgrep" (timeout/exec failure → info, do not gate verdict on
  it). Broadens the pgrep pattern to also catch processes whose argv
  carries the WhatsApp state-dir path so an embedded bridge inside the
  agent process still matches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
@yimoj yimoj force-pushed the fix/4386-whatsapp-inbound-diagnostics branch from 021096c to fc54994 Compare May 28, 2026 17:30
Comment thread src/lib/actions/sandbox/channel-status.ts Fixed
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/lib/actions/sandbox/channel-status.test.ts (1)

368-407: ⚡ Quick win

Always restore the process.exit spy via finally.

In this test, exitSpy.mockRestore() only runs on the happy path. If any expect or awaited call throws earlier, the mocked process.exit can leak into subsequent tests.

Proposed fix
-    const exitSpy = vi
-      .spyOn(process, "exit")
-      .mockImplementation(((code?: number) => {
-        throw new Error(`process.exit(${code})`);
-      }) as never);
-    const { deps: depsNoMatch, out_lines: linesNoMatch } = makeDeps({
-      exec: () => ({ status: 0, stdout: stdoutNoMatch, stderr: "" }),
-    });
-    try {
-      await showSandboxChannelStatus("alpha", { deps: depsNoMatch });
-    } catch {
-      /* expected exit(1) for stale-heartbeat + no bridge */
-    }
-    const dumpNoMatch = linesNoMatch.join("\n");
-    expect(dumpNoMatch).toMatch(/Bridge process: no WhatsApp bridge process observed/);
-    expect(dumpNoMatch).toMatch(/Verdict:.*idle/);
+    const exitSpy = vi
+      .spyOn(process, "exit")
+      .mockImplementation(((code?: number) => {
+        throw new Error(`process.exit(${code})`);
+      }) as never);
+    try {
+      const { deps: depsNoMatch, out_lines: linesNoMatch } = makeDeps({
+        exec: () => ({ status: 0, stdout: stdoutNoMatch, stderr: "" }),
+      });
+      try {
+        await showSandboxChannelStatus("alpha", { deps: depsNoMatch });
+      } catch {
+        /* expected exit(1) for stale-heartbeat + no bridge */
+      }
+      const dumpNoMatch = linesNoMatch.join("\n");
+      expect(dumpNoMatch).toMatch(/Bridge process: no WhatsApp bridge process observed/);
+      expect(dumpNoMatch).toMatch(/Verdict:.*idle/);
 
-    const stdoutTimeout = [
-      "NEMOCLAW_WA_DIAG_OK",
-      "DIR /sandbox/.openclaw/whatsapp POPULATED",
-      "NEMOCLAW_WA_HEARTBEAT_BEGIN",
-      JSON.stringify({
-        lastInboundAt: "2026-05-28T03:59:30.000Z",
-        messagesHandled: 1,
-        connectionState: "open",
-      }),
-      "NEMOCLAW_WA_HEARTBEAT_END",
-      "NEMOCLAW_WA_LOG_BEGIN",
-      "NEMOCLAW_WA_LOG_END",
-      // No PROC_DONE — simulating a probe that aborted before reaching
-      // the pgrep stage.
-    ].join("\n");
-    const { deps: depsTimeout, out_lines: linesTimeout } = makeDeps({
-      exec: () => ({ status: 0, stdout: stdoutTimeout, stderr: "" }),
-    });
-    await showSandboxChannelStatus("alpha", { deps: depsTimeout });
-    const dumpTimeout = linesTimeout.join("\n");
-    expect(dumpTimeout).toMatch(/Bridge process: could not enumerate sandbox processes/);
-    expect(dumpTimeout).toMatch(/Verdict:.*healthy/);
-    exitSpy.mockRestore();
+      const stdoutTimeout = [
+        "NEMOCLAW_WA_DIAG_OK",
+        "DIR /sandbox/.openclaw/whatsapp POPULATED",
+        "NEMOCLAW_WA_HEARTBEAT_BEGIN",
+        JSON.stringify({
+          lastInboundAt: "2026-05-28T03:59:30.000Z",
+          messagesHandled: 1,
+          connectionState: "open",
+        }),
+        "NEMOCLAW_WA_HEARTBEAT_END",
+        "NEMOCLAW_WA_LOG_BEGIN",
+        "NEMOCLAW_WA_LOG_END",
+        // No PROC_DONE — simulating a probe that aborted before reaching
+        // the pgrep stage.
+      ].join("\n");
+      const { deps: depsTimeout, out_lines: linesTimeout } = makeDeps({
+        exec: () => ({ status: 0, stdout: stdoutTimeout, stderr: "" }),
+      });
+      await showSandboxChannelStatus("alpha", { deps: depsTimeout });
+      const dumpTimeout = linesTimeout.join("\n");
+      expect(dumpTimeout).toMatch(/Bridge process: could not enumerate sandbox processes/);
+      expect(dumpTimeout).toMatch(/Verdict:.*healthy/);
+    } finally {
+      exitSpy.mockRestore();
+    }
🤖 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/channel-status.test.ts` around lines 368 - 407, The
test currently mocks process.exit with exitSpy but only calls
exitSpy.mockRestore() on the happy path, which can leak the mock if an assertion
or awaited call throws; wrap the exercised calls (the first try/catch, the
subsequent await showSandboxChannelStatus and all expects) in a try/finally and
call exitSpy.mockRestore() in the finally block so process.exit is always
restored; reference the existing exitSpy (spyOn(process, "exit")), the
showSandboxChannelStatus calls, and the makeDeps usage to locate where to add
the try/finally.
🤖 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 `@src/lib/actions/sandbox/channel-status.test.ts`:
- Around line 368-407: The test currently mocks process.exit with exitSpy but
only calls exitSpy.mockRestore() on the happy path, which can leak the mock if
an assertion or awaited call throws; wrap the exercised calls (the first
try/catch, the subsequent await showSandboxChannelStatus and all expects) in a
try/finally and call exitSpy.mockRestore() in the finally block so process.exit
is always restored; reference the existing exitSpy (spyOn(process, "exit")), the
showSandboxChannelStatus calls, and the makeDeps usage to locate where to add
the try/finally.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7939be4d-26de-4e0d-8468-c55a5d31fdde

📥 Commits

Reviewing files that changed from the base of the PR and between 021096c and fc54994.

📒 Files selected for processing (12)
  • docs/reference/commands.mdx
  • src/commands/sandbox/channels/status.ts
  • src/lib/actions/sandbox/channel-status.test.ts
  • src/lib/actions/sandbox/channel-status.ts
  • src/lib/actions/sandbox/doctor.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/cli/command-registry.test.ts
  • src/lib/cli/public-display-defaults.ts
  • src/lib/onboard/messaging-channel-setup.ts
  • src/lib/sandbox/channels.ts
  • src/lib/sandbox/whatsapp-diagnostics.test.ts
  • src/lib/sandbox/whatsapp-diagnostics.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/reference/commands.mdx
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/lib/cli/command-registry.test.ts
  • src/lib/onboard/messaging-channel-setup.ts
  • src/lib/cli/public-display-defaults.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/sandbox/channels.ts
  • src/commands/sandbox/channels/status.ts
  • src/lib/actions/sandbox/doctor.ts
  • src/lib/sandbox/whatsapp-diagnostics.ts
  • src/lib/actions/sandbox/channel-status.ts
  • src/lib/sandbox/whatsapp-diagnostics.test.ts

CodeRabbit nit on PR NVIDIA#4406: the new "distinguishes pgrep no-match from
probe abort" test mocked `process.exit` but only called
`exitSpy.mockRestore()` on the happy path. If any assertion threw,
the mock would leak into subsequent tests. Wrap the body in
try/finally so the spy is always restored.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Yimo Jiang <yimoj@nvidia.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

@wscurran wscurran added fix integration: whatsapp WhatsApp integration or channel behavior NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). labels May 28, 2026
@wscurran
Copy link
Copy Markdown
Contributor

@cv cv merged commit bb10a84 into NVIDIA:main May 29, 2026
22 checks passed
@wscurran wscurran added area: cli Command line interface, flags, terminal UX, or output bug-fix PR fixes a bug or regression labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command line interface, flags, terminal UX, or output bug-fix PR fixes a bug or regression fix integration: whatsapp WhatsApp integration or channel behavior NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). v0.0.56 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Brev][Agent&UX] WhatsApp inbound messages not received despite active Noise protocol WebSocket and successful pairing

5 participants