Skip to content

refactor(messaging): finish manifest channel migration#5338

Merged
cv merged 22 commits into
mainfrom
refactor/messaging-channel-manifest-stragglers
Jun 15, 2026
Merged

refactor(messaging): finish manifest channel migration#5338
cv merged 22 commits into
mainfrom
refactor/messaging-channel-manifest-stragglers

Conversation

@sandl99

@sandl99 sandl99 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR completes the messaging channel decoupling by routing channel-specific lifecycle behavior through manifests, hooks, and shared messaging helpers. It removes remaining core assumptions about concrete Telegram, WeChat, Slack, Discord, and WhatsApp implementations so core flows can operate from the manifest registry.

Close

Closes #4397

Changes

  • Adds manifest/applier hook phase coverage plus channel metadata and status helpers under src/lib/messaging/.
  • Moves runtime preload, health/status, policy preset, credential, rebuild, snapshot, and diagnostics call sites toward manifest-backed channel registries.
  • Migrates Slack socket-mode gateway conflict handling and channel runtime details into channel hooks/manifests without hard-coding Slack in core conflict code.
  • Replaces legacy WeChat-specific onboard config plumbing with manifest-backed messaging config and shared validation paths.
  • Updates migration notes and expands tests for hook phases, manifest metadata, plan validation, channel status, startup/runtime envs, and CLI fixture stability.

Verification

OpenClaw

Telegram

image #### Discord image #### WeChat image

Slack

image

Hermes

Telegram

image #### Discord image #### Slack image #### WeChat image

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Verification

  • npx prek run --all-files passes
  • npm test passes
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: San Dang sdang@nvidia.com

Summary by CodeRabbit

Release Notes

  • New Features

    • Expanded messaging diagnostics/health checks with spec-driven, per-channel reporting and deeper probe support.
    • Added manifest-driven messaging runtime setup (env aliases, secret scans, and runtime preloads).
    • Introduced new Slack and Telegram messaging status hooks (gateway conflict/status and bridge health).
  • Improvements

    • Generalized channel status/doctor output to follow built-in diagnostics.
    • Refactored channel enablement conflict detection to use pre-enable hook checks.
    • Improved messaging plan persistence/rehydration and runtime visibility metadata.
  • Bug Fixes

    • Strengthened bridge startup detection, gateway log probing, and conflict handling behavior.

@sandl99 sandl99 self-assigned this Jun 12, 2026
@coderabbitai

coderabbitai Bot commented Jun 12, 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
📝 Walkthrough

Walkthrough

Messaging setup, hooks, status checks, persistence, and startup flows now derive channel behavior from manifests and runtime plans. The PR also updates Docker/build staging, onboarding helpers, and tests to use the new messaging runtime metadata and preload pipeline.

Changes

Messaging manifest migration

Layer / File(s) Summary
Metadata and policy foundations
src/lib/messaging/channels/*, src/lib/onboard/*, src/lib/policy/index.ts, src/lib/sandbox/channels.ts, src/lib/security/redact.ts
Messaging diagnostics, config env keys, credential ownership, policy preset metadata, and onboarding config/drift handling now derive from built-in channel manifests.
Status and hook orchestration
src/lib/status-command-deps.ts, src/lib/inventory/index.ts, src/lib/messaging/applier/*, src/lib/actions/sandbox/*
Status checks, overlap reporting, doctor output, pre-enable checks, and post-rebuild health checks now run through manifest-defined hook phases and diagnostic specs.
Channel manifests and hooks
src/lib/messaging/channels/{discord,slack,telegram,wechat,whatsapp}/**, src/lib/messaging/manifest/types.ts, src/lib/messaging/channels/manifests.test.ts
Channel manifests add runtime visibility, preloads, agent packages, and health/status or pre-enable hooks, with new Slack, Telegram, and Discord hook implementations and updated manifest tests.
Plan compilation and onboarding integration
src/lib/messaging/{compiler,persistence,plan-validation}.ts, src/lib/onboard/..., src/lib/actions/sandbox/{rebuild,snapshot}.ts
Compiled messaging plans now carry runtimeSetup, expanded persisted shapes, derived hydration, filtered build patch config, primary credential selection, and manifest-backed onboarding/sandbox cleanup behavior.
Startup runtime pipeline and preloads
scripts/nemoclaw-start.sh, scripts/lib/sandbox-init.sh, Dockerfile, src/lib/messaging/channels/*/runtime/*, test/nemoclaw-start*.test.ts
Startup scripts write runtime setup plans, apply env aliases, install runtime preloads, export connect-shell NODE_OPTIONS, verify secret scans, and use runtime preload modules staged into the image.
Ancillary test and CI updates
.github/workflows/e2e-vitest-scenarios.yaml, ci/*, test/cli/*, test/*cleanup*, src/lib/inference/nim.test.ts
Workflow duplicate detection, help text, timeout wrappers, cleanup expectations, and several harness assertions are adjusted to match the updated messaging and runtime flows.

Sequence Diagram(s)

sequenceDiagram
  participant Dockerfile
  participant BuildApplier as messaging-build-applier.mts
  participant StartScript as scripts/nemoclaw-start.sh
  participant Sandbox

  Dockerfile->>BuildApplier: run --phase runtime-setup
  BuildApplier-->>Dockerfile: write runtime plan artifact
  StartScript->>StartScript: read plan from env or artifact
  StartScript->>StartScript: apply env aliases and install preloads
  StartScript->>Sandbox: start with secret scans and NODE_OPTIONS
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#4949: Both changes use NEMOCLAW_MESSAGING_PLAN_B64 and build/runtime messaging plan generation paths.
  • NVIDIA/NemoClaw#5328: Both modify messaging plan persistence, hydration, and derived plan field reconstruction.
  • NVIDIA/NemoClaw#5039: Both touch Slack Socket Mode conflict handling and related overlap/reporting code paths.

Suggested reviewers

  • cv

Poem

🐇 I packed a plan in a burrow of code,
with hooks and preloads along the road.
The channels now follow a manifest map,
while scripts take a neat little runtime nap.
Carrot cheers for each tidy scan—
hop, hop, hooray for the messaging plan!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/messaging-channel-manifest-stragglers

@sandl99 sandl99 added area: messaging Messaging channels, bridges, manifests, or channel lifecycle refactor PR restructures code without intended behavior change labels Jun 12, 2026
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: messaging-providers-e2e, channels-add-remove-e2e, rebuild-openclaw-e2e, openclaw-onboard-security-posture-e2e, network-policy-e2e, diagnostics-e2e, credential-migration-e2e, inference-routing-e2e
Optional E2E: token-rotation-e2e, channels-stop-start-openclaw-e2e, messaging-compatible-endpoint-e2e, openclaw-slack-pairing-e2e, openclaw-discord-pairing-e2e, cloud-e2e

Dispatch hint: messaging-providers-e2e,channels-add-remove-e2e,rebuild-openclaw-e2e,openclaw-onboard-security-posture-e2e,network-policy-e2e,diagnostics-e2e,credential-migration-e2e,inference-routing-e2e

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • messaging-providers-e2e (high): Merge-blocking because the PR changes the core messaging manifest compiler/applier, channel manifests, runtime preloads, provider placeholder refresh, diagnostics, and token isolation paths. This job validates Telegram, Discord, Slack, and WhatsApp provider/placeholder/L7-proxy behavior in a real OpenShell sandbox.
  • channels-add-remove-e2e (high): Required because channel add/remove, policy-channel, host-state applier, onboarding messaging reuse, and rebuild handoff changed. This covers the user flow of adding a channel after onboard, rebuilding, verifying gateway/policy/sandbox state, and removing it cleanly.
  • rebuild-openclaw-e2e (high): Required because Dockerfile runtime artifacts, sandbox build context, messaging runtime-plan persistence, provider placeholder refresh, and src/lib/actions/sandbox/rebuild.ts changed. The job verifies an existing OpenClaw sandbox rebuild preserves state, policies, config hashes, and gateway token behavior.
  • openclaw-onboard-security-posture-e2e (high): Required because install.sh, onboarding state handlers, Dockerfile image assembly, sandbox init/start, credential support, and redaction/security-boundary code changed. This gives a full OpenClaw install/onboard/security-posture run on a non-root host user.
  • network-policy-e2e (medium): Required because the WeChat preset and policy-channel/conflict code changed and messaging manifests now drive policy application. This validates live allow/deny behavior through the OpenShell policy boundary.
  • diagnostics-e2e (medium): Required because doctor, channel-status, channel-runtime-status, Telegram/WeChat diagnostics, bridge health hooks, and startup breadcrumbs changed. This validates user-visible diagnostics against a real sandbox rather than only unit-level log assertions.
  • credential-migration-e2e (medium): Required because credential store/command support and placeholder refresh/security scanning changed. This checks legacy credential migration, provider isolation, secure deletion, and symlink-safe credential handling at the OpenShell boundary.
  • inference-routing-e2e (medium): Required because onboarding/config generation and runtime startup changes can alter inference.local routing and secret isolation for model credentials, including messaging-compatible agent turns.

Optional E2E

  • token-rotation-e2e (high): Good adjacent confidence for the changed provider placeholder refresh and generic credential-binding logic, especially across Telegram/Discord/Slack token updates and re-onboard/rebuild cycles.
  • channels-stop-start-openclaw-e2e (high): Useful adjacent lifecycle coverage for changed channel status, persistence, disabled-channel handling, and cached credential reuse, but less directly targeted than add/remove and rebuild.
  • messaging-compatible-endpoint-e2e (medium): Useful for Telegram plus inference.local end-to-end behavior after changes to Telegram diagnostics/hooks, messaging runtime setup, and inference routing, but can be secondary if messaging-providers and inference-routing pass.
  • openclaw-slack-pairing-e2e (medium): Useful targeted Slack Socket Mode confidence because Slack manifest/hooks/runtime guard behavior changed, but the core fake-token provider path is covered by messaging-providers-e2e.
  • openclaw-discord-pairing-e2e (medium): Useful targeted Discord bridge confidence because Discord manifest and bridge-health hook code changed, but less central than the provider and channel lifecycle jobs.
  • cloud-e2e (high): Broad install/onboard/live assistant smoke for the default OpenClaw user journey after large Dockerfile, install, onboard, sandbox, and runtime script changes.

New E2E recommendations

  • WeChat messaging channel (high): The PR changes WeChat manifest, login/QR helpers, runtime diagnostics, preset policy, and onboard config, but the existing E2E inventory appears to cover Telegram/Discord/Slack plus WhatsApp QR parity more directly than a hermetic or live WeChat iLink/QR startup path.
    • Suggested test: Add a WeChat channel E2E that onboards or channels-adds WeChat with a hermetic QR/iLink fixture, verifies generated OpenClaw config and policy preset application, confirms runtime diagnostics/preload installation, and checks raw-token/QR-secret isolation.
  • manifest-driven runtime preload packaging (medium): This PR moves channel runtime preloads from blueprint scripts to TypeScript-compiled manifest metadata. Existing provider E2Es exercise major channels, but a focused E2E artifact check would catch missing compiled preload files or NODE_OPTIONS injection regressions before bridge startup.
    • Suggested test: Add a focused OpenClaw sandbox E2E that enables multiple channels and asserts the manifest-declared nodePreloads/envAliases/secretScans are materialized under /tmp, injected into gateway/connect scopes, and absent when a channel is disabled.

Dispatch hint

  • Workflow: nightly-e2e.yaml
  • jobs input: messaging-providers-e2e,channels-add-remove-e2e,rebuild-openclaw-e2e,openclaw-onboard-security-posture-e2e,network-policy-e2e,diagnostics-e2e,credential-migration-e2e,inference-routing-e2e

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Recommendation

Required Vitest E2E scenarios: None
Optional Vitest E2E scenarios: None

Workflow run

Full Vitest E2E advisor summary

Vitest E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required Vitest E2E scenarios

  • None. test/e2e-scenario/live/whatsapp-qr-compact.test.ts is a free-standing live Vitest file but is not referenced by .github/workflows/e2e-vitest-scenarios.yaml and is not registry-scenarios.test.ts. It must be wired into e2e-vitest-scenarios.yaml before it can be dispatched; the typed-scenario fan-out should not be used as proof for this changed live test.

Optional Vitest E2E scenarios

  • None.

Relevant changed files

  • .github/workflows/e2e-vitest-scenarios.yaml
  • test/e2e-scenario/live/whatsapp-qr-compact.test.ts
  • test/e2e-scenario/support-tests/e2e-fixture-context.test.ts
  • test/e2e-scenario/support-tests/e2e-scenarios-workflow.test.ts
  • test/e2e-scenario/support-tests/e2e-shell-supervisor.test.ts

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor

Findings: 0 needs attention, 7 worth checking, 0 nice ideas
Since last review: 1 prior item resolved, 0 still apply, 5 new items found

Review findings

🛠️ Needs attention

  • None.

🔎 Worth checking

  • Source-of-truth review needed: Manifest runtime setup artifact fallback: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: scripts/nemoclaw-start.sh loads `${NEMOCLAW_MESSAGING_RUNTIME_PLAN_PATH:-/usr/local/share/nemoclaw/messaging-runtime-plan.json}` after preferring NEMOCLAW_MESSAGING_PLAN_B64.
  • Source-of-truth review needed: Slack channel guard and deny-feedback runtime patch: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: src/lib/messaging/channels/slack/runtime/slack-channel-guard.ts patches process.emit and Module loaders; the manifest injects `slack-channel-guard` at boot/connect.
  • Type-check the Slack gateway preload (src/lib/messaging/channels/slack/runtime/slack-channel-guard.ts:1): This gateway NODE_OPTIONS preload is committed with @ts-nocheck while it monkeypatches process.emit, Module._extensions[".js"], and Module.registerHooks, and rewrites upstream Slack source at load time. That is a high-trust sandbox runtime boundary, so disabling type checking weakens the safety benefits of moving the preload to TypeScript.
    • Recommendation: Remove @ts-nocheck and type the small set of dynamic Node/module APIs, or replace it with narrow line-level suppressions that explain why each dynamic access is safe.
    • Evidence: The file starts with `// @ts-nocheck`; later code installs Slack deny-feedback hooks through `Module._extensions[".js"]` and `Module.registerHooks`, and the manifest injects this preload for OpenClaw boot/connect.
  • Add negative tests for tampered runtime setup plans (scripts/nemoclaw-start.sh:1488): The new manifest runtime setup plan controls gateway NODE_OPTIONS preloads, env aliases, and secret scans. The implementation validates paths, control characters, regexes, injectInto scopes, and scan paths, but the inspected tests mostly cover successful install/use paths and Slack secret scanning rather than a malicious-plan rejection matrix.
    • Recommendation: Add focused tests that fail before emitting NODE_OPTIONS when a runtime setup entry has a preload source outside /usr/local/lib/nemoclaw/preloads/, a target outside /tmp/nemoclaw-*.js, newline/tab characters in messages or alias values, an unsupported injectInto value, an invalid env key/regex, or a secret scan path outside /sandbox/.
    • Evidence: `write_messaging_runtime_setup_plan()` validates runtimeSetup before writing /tmp/nemoclaw-messaging-runtime-setup.json, and `install_messaging_runtime_preloads()` appends `--require $_target`; tests cover positive Slack/Telegram install and secret scanning but no full malicious-field rejection matrix was found.
  • Guard against runtime preload basename collisions (Dockerfile:553): The Docker build flattens compiled channel runtime preload files by basename into /usr/local/lib/nemoclaw/preloads/. If two channels later add runtime files with the same basename, one preload can silently overwrite the other and the manifest may point at the wrong code.
    • Recommendation: Fail the image build or add a manifest/package invariant test when two compiled `*/runtime/*.js` files resolve to the same basename. Alternatively, preserve a channel-qualified directory/name in the generated preload target.
    • Evidence: Dockerfile copies compiled files with `cp "$file" "/usr/local/lib/nemoclaw/preloads/$(basename "$file")"`; current built-in module names are unique, but no uniqueness guard was identified.
  • Split the expanded messaging persistence and hydration module (src/lib/messaging/persistence.ts:1): This refactor centralizes compact persistence, manifest-derived hydration, runtime setup fallback, and plan reconstruction in a file that grew from about 195 to 780 lines. That makes security-sensitive fallback and credential-placeholder behavior harder to audit and more likely to regress.
    • Recommendation: Extract the compact persistence serializer, manifest hydration/reconstruction, and runtime setup/state-update helpers into smaller modules with targeted tests around each boundary.
    • Evidence: The drift analysis reported `src/lib/messaging/persistence.ts` grew by 585 lines; inspected code now includes compact plan persistence plus manifest-backed hydration of networkPolicy, agentRender, buildSteps, runtimeSetup, stateUpdates, and healthChecks.
  • Document removal conditions for runtime setup fallbacks and diagnostics monkeypatches (scripts/nemoclaw-start.sh:1480): Several runtime setup paths are compatibility fallbacks or monkeypatches: the baked messaging runtime plan artifact is used when NEMOCLAW_MESSAGING_PLAN_B64 is absent, and Slack/Telegram/WeChat diagnostics are injected through NODE_OPTIONS. The invalid states and tests are mostly clear, but the artifact fallback and some diagnostics do not state when they can be removed or replaced at the source.
    • Recommendation: For each fallback/monkeypatch, add a short source-of-truth note covering the upstream/source boundary, why it cannot be fixed here, the regression test that owns it, and the removal condition. The WhatsApp QR preload is a good model.
    • Evidence: The start script comments say the entrypoint prefers a forwarded env plan and otherwise loads `/usr/local/share/nemoclaw/messaging-runtime-plan.json`; Slack/Telegram/WeChat runtime preloads are manifest-declared NODE_OPTIONS patches, while the WhatsApp preload explicitly documents a removal criterion.

🌱 Nice ideas

  • None.
Consider writing more tests for
  • **Runtime validation** — Reject runtime setup plan entries with preload source outside /usr/local/lib/nemoclaw/preloads/, target outside /tmp/nemoclaw-*.js, unsupported injectInto, invalid env key/regex, control characters, or secret scan path outside /sandbox/.. The PR changes Docker image packaging, sandbox entrypoint runtime preloads, credential placeholder refresh, manifest compilation, and workflow inventory parsing. Unit and shell-fragment tests are substantial, but the new gateway runtime setup path still deserves malicious-input and image/runtime validation.
  • **Runtime validation** — Fail or detect duplicate compiled channel runtime preload basenames before Docker flattens them into /usr/local/lib/nemoclaw/preloads/.. The PR changes Docker image packaging, sandbox entrypoint runtime preloads, credential placeholder refresh, manifest compilation, and workflow inventory parsing. Unit and shell-fragment tests are substantial, but the new gateway runtime setup path still deserves malicious-input and image/runtime validation.
  • **Runtime validation** — Boot a sandbox image with active Slack, Telegram, and WhatsApp channels and verify manifest-declared preloads are installed from the baked runtime artifact as root-owned 0444 files.. The PR changes Docker image packaging, sandbox entrypoint runtime preloads, credential placeholder refresh, manifest compilation, and workflow inventory parsing. Unit and shell-fragment tests are substantial, but the new gateway runtime setup path still deserves malicious-input and image/runtime validation.
  • **Runtime validation** — Exercise NEMOCLAW_MESSAGING_RUNTIME_PLAN_PATH with a tampered artifact and confirm validation fails before NODE_OPTIONS is extended.. The PR changes Docker image packaging, sandbox entrypoint runtime preloads, credential placeholder refresh, manifest compilation, and workflow inventory parsing. Unit and shell-fragment tests are substantial, but the new gateway runtime setup path still deserves malicious-input and image/runtime validation.
  • **Add negative tests for tampered runtime setup plans** — Add focused tests that fail before emitting NODE_OPTIONS when a runtime setup entry has a preload source outside /usr/local/lib/nemoclaw/preloads/, a target outside /tmp/nemoclaw-*.js, newline/tab characters in messages or alias values, an unsupported injectInto value, an invalid env key/regex, or a secret scan path outside /sandbox/.
  • **Manifest runtime setup artifact fallback** — test/nemoclaw-start-telegram-runtime.test.ts covers loading Telegram diagnostics from the baked runtime artifact when the env plan is absent.. scripts/nemoclaw-start.sh loads `${NEMOCLAW_MESSAGING_RUNTIME_PLAN_PATH:-/usr/local/share/nemoclaw/messaging-runtime-plan.json}` after preferring NEMOCLAW_MESSAGING_PLAN_B64.
  • **Slack channel guard and deny-feedback runtime patch** — test/nemoclaw-start.test.ts covers Slack auth safety-net behavior; test/openclaw-slack-deny-feedback-patch.test.ts covers CJS/ESM source patching, idempotence, bounded feedback, and fail-loud source-shape drift.. src/lib/messaging/channels/slack/runtime/slack-channel-guard.ts patches process.emit and Module loaders; the manifest injects `slack-channel-guard` at boot/connect.
Since last review details

Current findings:

  • Source-of-truth review needed: Manifest runtime setup artifact fallback: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: scripts/nemoclaw-start.sh loads `${NEMOCLAW_MESSAGING_RUNTIME_PLAN_PATH:-/usr/local/share/nemoclaw/messaging-runtime-plan.json}` after preferring NEMOCLAW_MESSAGING_PLAN_B64.
  • Source-of-truth review needed: Slack channel guard and deny-feedback runtime patch: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: src/lib/messaging/channels/slack/runtime/slack-channel-guard.ts patches process.emit and Module loaders; the manifest injects `slack-channel-guard` at boot/connect.
  • Type-check the Slack gateway preload (src/lib/messaging/channels/slack/runtime/slack-channel-guard.ts:1): This gateway NODE_OPTIONS preload is committed with @ts-nocheck while it monkeypatches process.emit, Module._extensions[".js"], and Module.registerHooks, and rewrites upstream Slack source at load time. That is a high-trust sandbox runtime boundary, so disabling type checking weakens the safety benefits of moving the preload to TypeScript.
    • Recommendation: Remove @ts-nocheck and type the small set of dynamic Node/module APIs, or replace it with narrow line-level suppressions that explain why each dynamic access is safe.
    • Evidence: The file starts with `// @ts-nocheck`; later code installs Slack deny-feedback hooks through `Module._extensions[".js"]` and `Module.registerHooks`, and the manifest injects this preload for OpenClaw boot/connect.
  • Add negative tests for tampered runtime setup plans (scripts/nemoclaw-start.sh:1488): The new manifest runtime setup plan controls gateway NODE_OPTIONS preloads, env aliases, and secret scans. The implementation validates paths, control characters, regexes, injectInto scopes, and scan paths, but the inspected tests mostly cover successful install/use paths and Slack secret scanning rather than a malicious-plan rejection matrix.
    • Recommendation: Add focused tests that fail before emitting NODE_OPTIONS when a runtime setup entry has a preload source outside /usr/local/lib/nemoclaw/preloads/, a target outside /tmp/nemoclaw-*.js, newline/tab characters in messages or alias values, an unsupported injectInto value, an invalid env key/regex, or a secret scan path outside /sandbox/.
    • Evidence: `write_messaging_runtime_setup_plan()` validates runtimeSetup before writing /tmp/nemoclaw-messaging-runtime-setup.json, and `install_messaging_runtime_preloads()` appends `--require $_target`; tests cover positive Slack/Telegram install and secret scanning but no full malicious-field rejection matrix was found.
  • Guard against runtime preload basename collisions (Dockerfile:553): The Docker build flattens compiled channel runtime preload files by basename into /usr/local/lib/nemoclaw/preloads/. If two channels later add runtime files with the same basename, one preload can silently overwrite the other and the manifest may point at the wrong code.
    • Recommendation: Fail the image build or add a manifest/package invariant test when two compiled `*/runtime/*.js` files resolve to the same basename. Alternatively, preserve a channel-qualified directory/name in the generated preload target.
    • Evidence: Dockerfile copies compiled files with `cp "$file" "/usr/local/lib/nemoclaw/preloads/$(basename "$file")"`; current built-in module names are unique, but no uniqueness guard was identified.
  • Split the expanded messaging persistence and hydration module (src/lib/messaging/persistence.ts:1): This refactor centralizes compact persistence, manifest-derived hydration, runtime setup fallback, and plan reconstruction in a file that grew from about 195 to 780 lines. That makes security-sensitive fallback and credential-placeholder behavior harder to audit and more likely to regress.
    • Recommendation: Extract the compact persistence serializer, manifest hydration/reconstruction, and runtime setup/state-update helpers into smaller modules with targeted tests around each boundary.
    • Evidence: The drift analysis reported `src/lib/messaging/persistence.ts` grew by 585 lines; inspected code now includes compact plan persistence plus manifest-backed hydration of networkPolicy, agentRender, buildSteps, runtimeSetup, stateUpdates, and healthChecks.
  • Document removal conditions for runtime setup fallbacks and diagnostics monkeypatches (scripts/nemoclaw-start.sh:1480): Several runtime setup paths are compatibility fallbacks or monkeypatches: the baked messaging runtime plan artifact is used when NEMOCLAW_MESSAGING_PLAN_B64 is absent, and Slack/Telegram/WeChat diagnostics are injected through NODE_OPTIONS. The invalid states and tests are mostly clear, but the artifact fallback and some diagnostics do not state when they can be removed or replaced at the source.
    • Recommendation: For each fallback/monkeypatch, add a short source-of-truth note covering the upstream/source boundary, why it cannot be fixed here, the regression test that owns it, and the removal condition. The WhatsApp QR preload is a good model.
    • Evidence: The start script comments say the entrypoint prefers a forwarded env plan and otherwise loads `/usr/local/share/nemoclaw/messaging-runtime-plan.json`; Slack/Telegram/WeChat runtime preloads are manifest-declared NODE_OPTIONS patches, while the WhatsApp preload explicitly documents a removal criterion.

Workflow run details

This is an automated advisory review. A human maintainer must make the final merge decision.

@sandl99 sandl99 changed the base branch from main to refactor/compact-messaging-persistence June 12, 2026 14:50
@sandl99 sandl99 changed the base branch from refactor/compact-messaging-persistence to main June 12, 2026 14:51
@sandl99 sandl99 marked this pull request as draft June 12, 2026 14:51
@copy-pr-bot

copy-pr-bot Bot commented Jun 12, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@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: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/nemoclaw-start.sh (1)

3567-3585: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Non-root one-shot commands still bypass the preload/security pipeline.

In the non-root path, exec "${NEMOCLAW_CMD[@]}" runs before install_messaging_runtime_preloads and verify_messaging_runtime_secret_scans. Root mode installs both before its one-shot command branch, so the two launch modes are no longer equivalent.

Suggested fix
   export_gateway_token
   write_messaging_runtime_preload_plan
   write_runtime_shell_env
   ensure_runtime_shell_env_shim
   lock_rc_files "$_SANDBOX_HOME" || true
   # Apply manifest-declared runtime env aliases before any child inherits the
   # env. This covers both one-shot commands and the gateway launch.
   apply_messaging_runtime_env_aliases
+  install_messaging_runtime_preloads
+  verify_messaging_runtime_secret_scans
 
   if [ ${`#NEMOCLAW_CMD`[@]} -gt 0 ]; then
     exec "${NEMOCLAW_CMD[@]}"
   fi
@@
-  install_messaging_runtime_preloads
-  verify_messaging_runtime_secret_scans

As per coding guidelines, scripts/nemoclaw-start.sh changes affect every sandbox boot and are invisible to unit tests.

🤖 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 `@scripts/nemoclaw-start.sh` around lines 3567 - 3585, The non-root one-shot
branch executes exec "${NEMOCLAW_CMD[@]}" before running
install_messaging_runtime_preloads and verify_messaging_runtime_secret_scans, so
non-root one-shot commands skip the preload/security pipeline; move the calls to
install_messaging_runtime_preloads and verify_messaging_runtime_secret_scans to
run before the conditional that checks NEMOCLAW_CMD (i.e., ensure
install_messaging_runtime_preloads and verify_messaging_runtime_secret_scans are
invoked prior to the exec "${NEMOCLAW_CMD[@]}" branch) so both root and non-root
one-shot launches run the same preload and secret-scan steps while preserving
the immediate exec behavior for one-shot commands.

Source: Coding guidelines

🧹 Nitpick comments (6)
src/lib/channel-runtime-status.test.ts (1)

153-156: ⚡ Quick win

Keep the token assertions tied to the grep pattern.

These checks now pass as long as each token appears anywhere in the generated script, so a regression in the actual grep -iwoE alternation could still slip through. Please bind the expectation to the grep expression itself instead of checking the substrings independently.

Possible tightening
-    expect(script).toContain("grep -iwoE '");
-    for (const token of ["telegram", "discord", "slack", "whatsapp", "wechat", "openclaw-weixin"]) {
-      expect(script).toContain(token);
-    }
+    expect(script).toMatch(
+      /grep -iwoE '.*telegram.*discord.*slack.*whatsapp.*wechat.*openclaw-weixin.*'/s,
+    );
🤖 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/channel-runtime-status.test.ts` around lines 153 - 156, The test
currently checks tokens separately, which allows them to appear anywhere;
instead assert that the exact grep alternation is present by verifying the
generated script contains the full "grep -iwoE '...'" pattern with tokens joined
by | (e.g., check that script includes "grep -iwoE
'telegram|discord|slack|whatsapp|wechat|openclaw-weixin'"); update the
assertions around the variable script (and any helper that builds the pattern)
to compare against that single grep expression rather than separate token
contains checks.
src/lib/inventory/index.test.ts (1)

488-495: ⚡ Quick win

Assert that the custom overlap message is actually used.

This mock now adds a manifest-supplied message, but the assertion still passes on generic Slack conflict wording. showStatusCommand() could ignore message entirely and this test would still stay green. Please assert the rendered line comes from the templated message path.

Possible tightening
-    expect(
-      lines.some((l) =>
-        l.includes("'alice' and 'bob' both have Slack Socket Mode enabled on the same gateway"),
-      ),
-    ).toBe(true);
+    expect(lines).toContain(
+      "  ⚠ 'alice' and 'bob' both have Slack Socket Mode enabled on the same gateway; only one sandbox can receive Slack Socket Mode events unless the gateway supports multiplexing.",
+    );

Also applies to: 511-515

🤖 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/inventory/index.test.ts` around lines 488 - 495, Update the test so
it verifies that showStatusCommand actually uses the manifest-supplied templated
message from the findMessagingOverlaps mock instead of falling back to the
generic wording: locate the mocked function findMessagingOverlaps in
src/lib/inventory/index.test.ts and change the assertion(s) that currently match
generic Slack conflict text to assert the rendered output contains the exact
templated string you added (e.g., the "'{first}' and '{second}' both have Slack
Socket Mode enabled..." message) so the test fails if showStatusCommand ignores
the message field; apply the same tighter assertion for the second case
mentioned around lines 511-515.
src/lib/messaging/channels/metadata.ts (1)

66-69: ⚡ Quick win

Rename listBuiltInMessagingChannelManifests or stop honoring options.manifests.

This helper returns arbitrary caller-supplied manifests when options.manifests is set, so the exported name is no longer accurate. That makes the public API misleading for callers reading the barrel surface.

🤖 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/messaging/channels/metadata.ts` around lines 66 - 69, The exported
function listBuiltInMessagingChannelManifests is misleading because it returns
caller-supplied manifests when options.manifests is provided; either stop
honoring options.manifests (so it truly only returns built-ins) or rename the
function to reflect that it honors caller manifests. Fix by either: 1) change
the implementation of listBuiltInMessagingChannelManifests to ignore
options.manifests and call selectManifests with an options object that does not
forward manifests (ensuring only built-in manifests are returned), or 2) rename
the function (and update all references/exports) to something like
listMessagingChannelManifests to indicate it may include supplied manifests;
update any barrel exports and docs accordingly. Ensure you update or preserve
all call-sites that reference listBuiltInMessagingChannelManifests or its
replacement.
test/sandbox-provider-cleanup.test.ts (1)

56-64: ⚡ Quick win

Make this detach-call assertion order-insensitive.

The test name only cares that every suffix is covered, but this comparison also locks in the current Set insertion order. A harmless reorder of SANDBOX_PROVIDER_SUFFIXES will fail the test without changing behavior.

Proposed fix
-    expect(detachCalls).toEqual(
-      SANDBOX_PROVIDER_SUFFIXES.map((suffix) => [
-        "sandbox",
-        "provider",
-        "detach",
-        "spark-nemo",
-        `spark-nemo-${suffix}`,
-      ]),
-    );
+    expect(detachCalls.map((argv) => argv.join(" ")).sort()).toEqual(
+      [...SANDBOX_PROVIDER_SUFFIXES]
+        .map((suffix) =>
+          [
+            "sandbox",
+            "provider",
+            "detach",
+            "spark-nemo",
+            `spark-nemo-${suffix}`,
+          ].join(" "),
+        )
+        .sort(),
+    );
🤖 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/sandbox-provider-cleanup.test.ts` around lines 56 - 64, The detach-call
assertion is order-sensitive; change it to compare the collections without
relying on insertion order by converting both actual detachCalls and the
expected SANDBOX_PROVIDER_SUFFIXES-derived arrays into order-insensitive sets
(e.g., map each sub-array to a stable string representation or sort by the
suffix and then compare as Sets) so the test verifies presence of every expected
["sandbox","provider","detach","spark-nemo",`spark-nemo-${suffix}`] tuple
regardless of order; update the assertion that references detachCalls and
SANDBOX_PROVIDER_SUFFIXES accordingly.
scripts/lib/sandbox-init.sh (1)

779-817: Please run the sandbox entrypoint E2Es for this change.

This path executes on every sandbox boot and is not meaningfully covered by unit tests, so I’d validate it with the entrypoint-focused jobs before merge:

gh workflow run nightly-e2e.yaml --ref <branch> -f jobs=sandbox-survival-e2e,sandbox-operations-e2e,cloud-e2e,openclaw-slack-pairing-e2e

As per coding guidelines, changes to scripts/lib/sandbox-init.sh should be verified with sandbox-survival-e2e, sandbox-operations-e2e, cloud-e2e, and openclaw-slack-pairing-e2e.

🤖 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 `@scripts/lib/sandbox-init.sh` around lines 779 - 817, This change touches the
sandbox boot path in scripts/lib/sandbox-init.sh (functions
configure_messaging_channels and read_messaging_plan_channels which read
NEMOCLAW_MESSAGING_PLAN_B64), so run the sandbox entrypoint E2E suites before
merging: trigger the nightly E2E workflow for the branch and validate jobs
sandbox-survival-e2e, sandbox-operations-e2e, cloud-e2e, and
openclaw-slack-pairing-e2e to ensure the messaging-channel parsing and startup
behavior are exercised end-to-end.

Source: Coding guidelines

src/lib/onboard/sandbox-messaging-preflight.test.ts (1)

41-52: ⚡ Quick win

Use the exported Slack hook handler constant in this fixture.

This test hardcodes "slack.socketModeGatewayConflict" even though the same contract is already imported via SLACK_SOCKET_MODE_GATEWAY_CONFLICT_HOOK_HANDLER_ID in src/lib/onboard/messaging-conflict-guard.test.ts. Reusing the shared symbol here keeps the fixture aligned with the production hook registry and avoids stale literals on future renames.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/onboard/sandbox-messaging-preflight.test.ts` around lines 41 - 52,
Replace the hardcoded hook handler string "slack.socketModeGatewayConflict" in
the test fixture with the shared exported constant
SLACK_SOCKET_MODE_GATEWAY_CONFLICT_HOOK_HANDLER_ID; add an import for
SLACK_SOCKET_MODE_GATEWAY_CONFLICT_HOOK_HANDLER_ID at the top of
src/lib/onboard/sandbox-messaging-preflight.test.ts and use that symbol where
the handler value is currently set so the fixture stays in sync with the
production hook registry.
🤖 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 `@scripts/nemoclaw-start.sh`:
- Around line 1498-1514: clean_env_alias currently validates envAliases[*].match
with Python re but apply_messaging_runtime_env_aliases uses Bash ERE, so change
validation in clean_env_alias to verify the pattern is valid under Bash ERE
(e.g., run a lightweight Bash test via subprocess that attempts a dummy [[ "" =~
"<pattern>" ]] or otherwise validate against POSIX/Bash ERE rules) and fail with
a clear message if Bash rejects it; and reorder the runtime pipeline so non-root
execution runs install_messaging_runtime_preloads and
verify_messaging_runtime_secret_scans before doing the exec in
apply_messaging_runtime_env_aliases/where non-root exec is triggered (move the
preload + secret-scan calls to precede the non-root exec path) to match
root-mode ordering.

In `@src/lib/actions/sandbox/policy-channel.ts`:
- Around line 491-495: The code calls createMessagingPreEnableHookInputs with
currentGatewayName always set to BASE_GATEWAY_NAME; instead, read the recorded
gateway name from the current sandbox registry entry (use the registry entry for
sandboxName from registryEntries) and pass that as currentGatewayName, falling
back to BASE_GATEWAY_NAME only if the sandbox entry has no gateway field; update
the additionalInputs call to use the sandbox's gateway value (from the registry
entry for sandboxName) rather than the hardcoded BASE_GATEWAY_NAME.

In `@src/lib/messaging/applier/hook-phases.ts`:
- Around line 66-77: The loop currently only skips the failing request when
requestWithInputs.onFailure === "skip-channel"; change it to stop all later
hooks for that channel by introducing a Set (e.g., skippedChannels) outside the
loop, check at the top of the for-loop and continue if
skippedChannels.has(request.channelId), and when catching an error for a request
with onFailure === "skip-channel" add requestWithInputs.channelId to
skippedChannels and record the skipped hook via
skippedHooks.push(formatHookKey(requestWithInputs)) before continuing; ensure
you reference hookRequests, requestWithInputs, requestWithInputs.onFailure,
skippedHooks, formatHookKey, and request.channelId in your changes.

In `@src/lib/messaging/channels/metadata.ts`:
- Around line 299-304: The code currently normalizes an omitted hook.agents to
an empty array, losing the original “all agents” semantics; update the object
returned in listMessagingPackageInstallSpecs() (the creation of
MessagingPackageInstallMetadata) to preserve that meaning by setting agents:
hook.agents ?? manifest.supportedAgents (or alternatively keep agents undefined
in the shape so downstream can treat undefined as “all agents”); ensure callers
that use hookTargetsAgent() continue to see undefined for universal installs or
that manifest.supportedAgents is supplied so semantics remain correct (reference
hook.agents, manifest.supportedAgents, packageInstallValue(value),
hookTargetsAgent(), and MessagingPackageInstallMetadata).
- Around line 240-260: Both helpers currently use Object.fromEntries on
listMessagingPolicyPresetMetadata() so later presets with the same
preset.presetName overwrite earlier ones; change getMessagingPolicyKeyAliases to
accumulate/merge entries by preset.presetName: for each preset combine
preset.policyKeys and all values from preset.agentPolicyKeys (flatten), append
to any existing list for that name, then run uniqueStrings once to dedupe before
returning the final map. Similarly change
getMessagingPolicyPresetValidationWarnings to concatenate
preset.validationWarningLines for duplicate preset.presetName (preserve order),
dedupe if needed, and return the merged map; use
listMessagingPolicyPresetMetadata() as the source and reference uniqueStrings,
preset.presetName, preset.policyKeys, preset.agentPolicyKeys, and
preset.validationWarningLines when implementing the merge.

In `@src/lib/messaging/status-outputs.ts`:
- Around line 38-55: The manifest list needs to be filtered by
manifest.supportedAgents when an agent is provided so manifests that don't
support the agent cannot contribute outputs; update
collectBuiltInMessagingStatusOutputs and/or collectMessagingStatusOutputs to
check manifest.supportedAgents (in addition to hook.agents) and skip manifests
where options.agent is set and not included in manifest.supportedAgents before
iterating manifest.hooks and hook.outputs; ensure you keep the existing per-hook
hook.agents check but apply the manifest-level filter first using the
createBuiltInChannelManifestRegistry().list() result (or inside
collectMessagingStatusOutputs) to locate the correct manifests to process.

In `@src/lib/onboard/docker-gpu-patch.ts`:
- Around line 531-535: The default for dockerDriverGateway is wrong: change the
fallback so dockerDriverGateway is derived from either linux platform or the WSL
flag; update the assignment of dockerDriverGateway (currently: const
dockerDriverGateway = options.dockerDriverGateway ?? platform === "linux") to
use options.dockerDriverGateway ?? (platform === "linux" || dockerDesktopWsl) so
that the dockerDesktopWsl true path enables the gateway when callers omit
dockerDriverGateway; keep the rest of the conditional using
config.sandboxGpuEnabled, platform/dockerDesktopWsl and dockerDriverGateway
unchanged.

In `@src/lib/onboard/messaging-conflict-guard.ts`:
- Around line 133-167: The catch currently treats every failure from
MessagingSetupApplier.applyPreEnableChecks as a user-overridable conflict;
change it to only handle the expected conflict/error shape and rethrow any other
errors so real infrastructure/programming failures surface. Concretely, inspect
the caught error from the applyPreEnableChecks call (the catch around
MessagingSetupApplier.applyPreEnableChecks) for the conflict-specific
fingerprint your hooks use (e.g., a property like error.type ===
"MessagingConflict" or error.isOverridableConflict or error.code ===
"CONFLICT"); only when that predicate is true run the existing logging,
deps.promptContinue flow and the abort/deps.error branches; otherwise
immediately rethrow the error so callers (or CI) see the original exception.
Ensure references to runMessagingHook, deps.promptContinue, deps.error, and
abort remain unchanged and only the catch behavior is gated by the conflict
check.

In `@src/lib/onboard/policy-presets.ts`:
- Around line 46-76: The code collapses multiple messaging credentials per
channel into a single env key via credentialsByChannel, causing preset
auto-detection to miss additional credentials; change credentialsByChannel to
collect all providerEnvKey values (e.g., Map<string, string[]> populated from
listMessagingCredentialMetadata()), and then when iterating presets from
listMessagingPolicyPresetMetadata() call maybeSuggestMessagingPreset for each
env key for that channel (or adjust maybeSuggestMessagingPreset to accept and
check an array of env keys), ensuring you still call getCredential(envKey) /
process.env[envKey] for each entry and preserve the existing TTY logging
behavior.

In `@src/lib/onboard/sandbox-build-patch-config.ts`:
- Around line 23-35: prepareSandboxBuildPatchConfig currently returns
messagingChannelConfig directly from readMessagingChannelConfigFromEnv, which
allows stale/unconfigured env keys to be baked in; fix this by enforcing the
manifest-backed allowlist: obtain the configuredMessagingChannels (either from a
new input param or via a provided dependency like
deps.readConfiguredMessagingChannelsFromManifest) and then filter the returned
messagingChannelConfig so only channels present in configuredMessagingChannels
are included before returning the SandboxBuildPatchConfig; update
PrepareSandboxBuildPatchConfigInput and call sites or add the deps helper as
needed and ensure you reference prepareSandboxBuildPatchConfig,
readMessagingChannelConfigFromEnv (or deps.readMessagingChannelConfigFromEnv),
and configuredMessagingChannels in your changes.

In `@src/lib/onboard/sandbox-create-plan.ts`:
- Around line 111-120: getPrimaryCredentialEnvKeys currently picks the first
providerEnvKey per channel by iterating listMessagingCredentialMetadata(), which
relies on unstable iteration order and can drop valid channels in
resolveActiveMessagingChannels/activeMessagingChannels; change
getPrimaryCredentialEnvKeys to select the primary credential deterministically:
prefer an explicit marker (e.g., metadata.isPrimary) on each credential and
choose that providerEnvKey for the channel, and if no marker exists fall back to
a stable tie-breaker (e.g., sort credentials for the channel by a stable field
like providerEnvKey or credentialId and pick the first), ensuring you reference
listMessagingCredentialMetadata(), getPrimaryCredentialEnvKeys(), and
resolveActiveMessagingChannels when making the change so the returned envKeys
are deterministic and stable.

In `@src/lib/sandbox/channels.ts`:
- Around line 118-143: The metadata from configFieldMetadata(manifest) is being
omitted for in-sandbox-qr channels; update the construction so
configFieldMetadata(manifest) is always merged into the ChannelBase (or at least
included in the in-sandbox-qr return) instead of conditionally excluding it when
manifest.auth.mode === "in-sandbox-qr". Specifically, change the spread that
currently uses ...(manifest.auth.mode === "in-sandbox-qr" ? {} :
configFieldMetadata(manifest)) so that configFieldMetadata(manifest) is applied
unconditionally (or added to the object returned inside the in-sandbox-qr
branch), ensuring getChannelDef/ChannelBase still expose userIdEnvKey/label/help
for in-sandbox-qr channels.

In `@src/lib/status-command-deps.ts`:
- Around line 29-30: STATUS_OUTPUTS is currently unfiltered and causes
duplicate/incorrect warnings; modify the code so the sandbox/entry agent is
threaded into checkMessagingBridgeHealth() and findMessagingOverlaps() and use
that agent to filter outputs returned by collectBuiltInMessagingStatusOutputs()
(or replace the global STATUS_OUTPUTS with a per-agent filtered set) before
passing them into those helpers; specifically locate STATUS_OUTPUTS and replace
its global usage with a call that accepts an agent identifier (from the
sandbox/entry context) and returns only outputs where output.agent === agent (or
matching agent predicate), then update checkMessagingBridgeHealth() and
findMessagingOverlaps() to accept the agent param and consume the filtered
outputs instead of the unscoped STATUS_OUTPUTS.

In `@test/sandbox-init.test.ts`:
- Around line 866-869: The test for "no messaging plan" can inherit
NEMOCLAW_MESSAGING_PLAN_B64 from the parent environment via runWithLib; update
the test so the env passed into runWithLib explicitly unsets that variable
(e.g., include NEMOCLAW_MESSAGING_PLAN_B64: undefined or remove it) before
invoking configure_messaging_channels so the path is hermetic and always
exercises the "no messaging plan" branch in
runWithLib/configure_messaging_channels.

---

Outside diff comments:
In `@scripts/nemoclaw-start.sh`:
- Around line 3567-3585: The non-root one-shot branch executes exec
"${NEMOCLAW_CMD[@]}" before running install_messaging_runtime_preloads and
verify_messaging_runtime_secret_scans, so non-root one-shot commands skip the
preload/security pipeline; move the calls to install_messaging_runtime_preloads
and verify_messaging_runtime_secret_scans to run before the conditional that
checks NEMOCLAW_CMD (i.e., ensure install_messaging_runtime_preloads and
verify_messaging_runtime_secret_scans are invoked prior to the exec
"${NEMOCLAW_CMD[@]}" branch) so both root and non-root one-shot launches run the
same preload and secret-scan steps while preserving the immediate exec behavior
for one-shot commands.

---

Nitpick comments:
In `@scripts/lib/sandbox-init.sh`:
- Around line 779-817: This change touches the sandbox boot path in
scripts/lib/sandbox-init.sh (functions configure_messaging_channels and
read_messaging_plan_channels which read NEMOCLAW_MESSAGING_PLAN_B64), so run the
sandbox entrypoint E2E suites before merging: trigger the nightly E2E workflow
for the branch and validate jobs sandbox-survival-e2e, sandbox-operations-e2e,
cloud-e2e, and openclaw-slack-pairing-e2e to ensure the messaging-channel
parsing and startup behavior are exercised end-to-end.

In `@src/lib/channel-runtime-status.test.ts`:
- Around line 153-156: The test currently checks tokens separately, which allows
them to appear anywhere; instead assert that the exact grep alternation is
present by verifying the generated script contains the full "grep -iwoE '...'"
pattern with tokens joined by | (e.g., check that script includes "grep -iwoE
'telegram|discord|slack|whatsapp|wechat|openclaw-weixin'"); update the
assertions around the variable script (and any helper that builds the pattern)
to compare against that single grep expression rather than separate token
contains checks.

In `@src/lib/inventory/index.test.ts`:
- Around line 488-495: Update the test so it verifies that showStatusCommand
actually uses the manifest-supplied templated message from the
findMessagingOverlaps mock instead of falling back to the generic wording:
locate the mocked function findMessagingOverlaps in
src/lib/inventory/index.test.ts and change the assertion(s) that currently match
generic Slack conflict text to assert the rendered output contains the exact
templated string you added (e.g., the "'{first}' and '{second}' both have Slack
Socket Mode enabled..." message) so the test fails if showStatusCommand ignores
the message field; apply the same tighter assertion for the second case
mentioned around lines 511-515.

In `@src/lib/messaging/channels/metadata.ts`:
- Around line 66-69: The exported function listBuiltInMessagingChannelManifests
is misleading because it returns caller-supplied manifests when
options.manifests is provided; either stop honoring options.manifests (so it
truly only returns built-ins) or rename the function to reflect that it honors
caller manifests. Fix by either: 1) change the implementation of
listBuiltInMessagingChannelManifests to ignore options.manifests and call
selectManifests with an options object that does not forward manifests (ensuring
only built-in manifests are returned), or 2) rename the function (and update all
references/exports) to something like listMessagingChannelManifests to indicate
it may include supplied manifests; update any barrel exports and docs
accordingly. Ensure you update or preserve all call-sites that reference
listBuiltInMessagingChannelManifests or its replacement.

In `@src/lib/onboard/sandbox-messaging-preflight.test.ts`:
- Around line 41-52: Replace the hardcoded hook handler string
"slack.socketModeGatewayConflict" in the test fixture with the shared exported
constant SLACK_SOCKET_MODE_GATEWAY_CONFLICT_HOOK_HANDLER_ID; add an import for
SLACK_SOCKET_MODE_GATEWAY_CONFLICT_HOOK_HANDLER_ID at the top of
src/lib/onboard/sandbox-messaging-preflight.test.ts and use that symbol where
the handler value is currently set so the fixture stays in sync with the
production hook registry.

In `@test/sandbox-provider-cleanup.test.ts`:
- Around line 56-64: The detach-call assertion is order-sensitive; change it to
compare the collections without relying on insertion order by converting both
actual detachCalls and the expected SANDBOX_PROVIDER_SUFFIXES-derived arrays
into order-insensitive sets (e.g., map each sub-array to a stable string
representation or sort by the suffix and then compare as Sets) so the test
verifies presence of every expected
["sandbox","provider","detach","spark-nemo",`spark-nemo-${suffix}`] tuple
regardless of order; update the assertion that references detachCalls and
SANDBOX_PROVIDER_SUFFIXES accordingly.
🪄 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: e6091b90-6d48-4a69-abd2-9a3023b24d94

📥 Commits

Reviewing files that changed from the base of the PR and between 7a038ec and b99378a.

📒 Files selected for processing (94)
  • ci/test-file-size-budget.json
  • scripts/install.sh
  • scripts/lib/sandbox-init.sh
  • scripts/nemoclaw-start.sh
  • src/lib/actions/sandbox/channel-status.ts
  • src/lib/actions/sandbox/doctor.ts
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/actions/sandbox/snapshot.ts
  • src/lib/actions/sandbox/telegram-channel-bridge-verification.test.ts
  • src/lib/actions/sandbox/telegram-channel-bridge-verification.ts
  • src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts
  • src/lib/channel-runtime-status.test.ts
  • src/lib/channel-runtime-status.ts
  • src/lib/credentials/command-support.ts
  • src/lib/credentials/store.ts
  • src/lib/inventory/index.test.ts
  • src/lib/inventory/index.ts
  • src/lib/messaging-channel-config.test.ts
  • src/lib/messaging-channel-config.ts
  • src/lib/messaging/MIGRATION.md
  • src/lib/messaging/applier/conflict-detection/manifest-metadata.ts
  • src/lib/messaging/applier/hook-phases.test.ts
  • src/lib/messaging/applier/hook-phases.ts
  • src/lib/messaging/applier/index.ts
  • src/lib/messaging/applier/setup-applier.test.ts
  • src/lib/messaging/applier/setup-applier.ts
  • src/lib/messaging/channels/built-ins.ts
  • src/lib/messaging/channels/discord/manifest.ts
  • src/lib/messaging/channels/index.ts
  • src/lib/messaging/channels/manifests.test.ts
  • src/lib/messaging/channels/metadata.test.ts
  • src/lib/messaging/channels/metadata.ts
  • src/lib/messaging/channels/slack/hooks/index.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.test.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.ts
  • src/lib/messaging/channels/slack/manifest.ts
  • src/lib/messaging/channels/telegram/manifest.ts
  • src/lib/messaging/channels/wechat/manifest.ts
  • src/lib/messaging/channels/whatsapp/manifest.ts
  • src/lib/messaging/compiler/manifest-compiler.test.ts
  • src/lib/messaging/diagnostics.test.ts
  • src/lib/messaging/diagnostics.ts
  • src/lib/messaging/hooks/hook-runner.test.ts
  • src/lib/messaging/index.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/messaging/plan-validation.test.ts
  • src/lib/messaging/plan-validation.ts
  • src/lib/messaging/status-outputs.ts
  • src/lib/onboard.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/onboard/initial-policy.ts
  • src/lib/onboard/machine/core-flow-phases.test.ts
  • src/lib/onboard/machine/handlers/sandbox.test.ts
  • src/lib/onboard/machine/handlers/sandbox.ts
  • src/lib/onboard/messaging-config.test.ts
  • src/lib/onboard/messaging-config.ts
  • src/lib/onboard/messaging-conflict-guard.test.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • src/lib/onboard/messaging-credentials.ts
  • src/lib/onboard/messaging-policy-presets.ts
  • src/lib/onboard/messaging-prep.test.ts
  • src/lib/onboard/messaging-prep.ts
  • src/lib/onboard/messaging-reuse.ts
  • src/lib/onboard/policy-presets.ts
  • src/lib/onboard/sandbox-build-patch-config.test.ts
  • src/lib/onboard/sandbox-build-patch-config.ts
  • src/lib/onboard/sandbox-create-plan.ts
  • src/lib/onboard/sandbox-messaging-preflight.test.ts
  • src/lib/onboard/sandbox-provider-cleanup.ts
  • src/lib/onboard/wechat-config.ts
  • src/lib/policy/index.ts
  • src/lib/sandbox/channels.test.ts
  • src/lib/sandbox/channels.ts
  • src/lib/security/redact.ts
  • src/lib/status-command-deps.test.ts
  • src/lib/status-command-deps.ts
  • test/channels-add-preset.test.ts
  • test/cli/connect-recovery.test.ts
  • test/cli/destroy-detach-order.test.ts
  • test/cli/doctor-gateway-token.test.ts
  • test/cli/logs.test.ts
  • test/cli/maintenance-command.test.ts
  • test/cli/snapshot-shields.test.ts
  • test/destroy-cleanup-sandbox-services.test.ts
  • test/e2e-scenario/support-tests/e2e-fixture-context.test.ts
  • test/e2e-scenario/support-tests/e2e-shell-supervisor.test.ts
  • test/nemoclaw-start-slack-runtime.test.ts
  • test/nemoclaw-start.test.ts
  • test/onboard-policy-suggestions.test.ts
  • test/sandbox-init.test.ts
  • test/sandbox-provider-cleanup.test.ts
  • test/whatsapp-qr-compact.test.ts
💤 Files with no reviewable changes (6)
  • src/lib/actions/sandbox/telegram-channel-bridge-verification.test.ts
  • test/e2e-scenario/support-tests/e2e-shell-supervisor.test.ts
  • src/lib/actions/sandbox/telegram-channel-bridge-verification.ts
  • src/lib/onboard/wechat-config.ts
  • src/lib/onboard/machine/core-flow-phases.test.ts
  • src/lib/onboard/machine/handlers/sandbox.ts

Comment thread scripts/nemoclaw-start.sh
Comment thread src/lib/actions/sandbox/policy-channel.ts
Comment thread src/lib/messaging/applier/hook-phases.ts
Comment thread src/lib/messaging/channels/metadata.ts Outdated
Comment thread src/lib/messaging/channels/metadata.ts Outdated
Comment thread src/lib/onboard/sandbox-build-patch-config.ts
Comment thread src/lib/onboard/sandbox-create-plan.ts
Comment thread src/lib/sandbox/channels.ts
Comment thread src/lib/status-command-deps.ts Outdated
Comment thread test/sandbox-init.test.ts

@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/messaging/channels/metadata.test.ts`:
- Around line 184-187: The helper manifestWithPreset currently types its preset
parameter as NonNullable<ChannelManifest["policyPresets"]>[number], which
prevents callers passing a string literal; change the signature of
manifestWithPreset to accept both forms by declaring the second parameter as
ChannelPolicyPresetReference (or explicitly string | ChannelPolicyPresetSpec)
and update any imports/types used so the function can accept either a preset
name string or a full ChannelPolicyPresetSpec object; keep the function body
unchanged so it works with both variants.
🪄 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: f7b5b8d9-2876-4cd0-be5f-af7c011bc457

📥 Commits

Reviewing files that changed from the base of the PR and between b99378a and 067ad60.

📒 Files selected for processing (35)
  • scripts/nemoclaw-start.sh
  • src/lib/actions/sandbox/doctor.ts
  • 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-channel-config.test.ts
  • src/lib/messaging/applier/hook-phases.test.ts
  • src/lib/messaging/applier/hook-phases.ts
  • src/lib/messaging/channels/manifests.test.ts
  • src/lib/messaging/channels/metadata.test.ts
  • src/lib/messaging/channels/metadata.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.test.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.ts
  • src/lib/messaging/channels/slack/manifest.ts
  • src/lib/messaging/hooks/errors.ts
  • src/lib/messaging/hooks/index.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/messaging/status-outputs.test.ts
  • src/lib/messaging/status-outputs.ts
  • src/lib/onboard/docker-gpu-patch-wsl.test.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/onboard/messaging-conflict-guard.test.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • src/lib/onboard/policy-presets.ts
  • src/lib/onboard/sandbox-build-patch-config.test.ts
  • src/lib/onboard/sandbox-build-patch-config.ts
  • src/lib/onboard/sandbox-create-plan.ts
  • src/lib/sandbox/channels.test.ts
  • src/lib/sandbox/channels.ts
  • src/lib/status-command-deps.ts
  • test/nemoclaw-start-runtime-env-alias.test.ts
  • test/nemoclaw-start.test.ts
  • test/onboard-policy-suggestions.test.ts
  • test/sandbox-init.test.ts
✅ Files skipped from review due to trivial changes (1)
  • src/lib/messaging/hooks/index.ts
🚧 Files skipped from review as they are similar to previous changes (22)
  • src/lib/messaging-channel-config.test.ts
  • src/lib/inventory/index.test.ts
  • src/lib/onboard/sandbox-create-plan.ts
  • src/lib/sandbox/channels.test.ts
  • src/lib/onboard/policy-presets.ts
  • src/lib/inventory/index.ts
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/onboard/sandbox-build-patch-config.ts
  • src/lib/messaging/applier/hook-phases.test.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.test.ts
  • src/lib/actions/sandbox/doctor.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.ts
  • src/lib/messaging/status-outputs.ts
  • src/lib/onboard/sandbox-build-patch-config.test.ts
  • src/lib/sandbox/channels.ts
  • src/lib/messaging/channels/manifests.test.ts
  • src/lib/messaging/applier/hook-phases.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • test/nemoclaw-start.test.ts
  • scripts/nemoclaw-start.sh

Comment thread src/lib/messaging/channels/metadata.test.ts Outdated
Comment thread src/lib/messaging/channels/metadata.ts Fixed
…annel-manifest-stragglers

# Conflicts:
#	src/lib/actions/sandbox/doctor.ts
#	src/lib/actions/sandbox/policy-channel-conflict.test.ts
#	src/lib/actions/sandbox/policy-channel.ts
#	src/lib/actions/sandbox/snapshot.ts
#	src/lib/messaging/applier/host-state-applier.ts
#	src/lib/messaging/plan-validation.ts
#	src/lib/sandbox/channels.ts
#	src/lib/security/redact.ts
#	test/cli/doctor-gateway-token.test.ts
@github-code-quality

github-code-quality Bot commented Jun 13, 2026

Copy link
Copy Markdown

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the branch is 96%. Coverage data for the branch is not yet available.

Show a code coverage summary of the most covered files.
File 9b85f89 +/-
nemoclaw/src/se...cret-scanner.ts 100%
nemoclaw/src/commands/slash.ts 100%
nemoclaw/src/li...bprocess-env.ts 100%
nemoclaw/src/bl...eprint/state.ts 98%
nemoclaw/src/onboard/config.ts 98%
nemoclaw/src/bl...int/snapshot.ts 97%
nemoclaw/src/bl...print/runner.ts 95%
nemoclaw/src/co...ration-state.ts 94%
nemoclaw/src/bl...ate-networks.ts 94%
nemoclaw/src/index.ts 94%

TypeScript / code-coverage/cli

The overall coverage in the branch is 44%. Coverage data for the branch is not yet available.

Show a code coverage summary of the most covered files.
File 9b85f89 +/-
src/lib/state/o...oard-session.ts 90%
src/lib/inference/local.ts 78%
src/lib/sandbox/config.ts 72%
src/lib/inference/nim.ts 72%
src/lib/onboard/preflight.ts 64%
src/lib/state/sandbox.ts 55%
src/lib/actions...licy-channel.ts 52%
src/lib/onboard...er-gpu-patch.ts 50%
src/lib/policy/index.ts 49%
src/lib/onboard.ts 17%

Updated June 15, 2026 05:06 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

Comment thread src/lib/messaging/channels/metadata.ts Fixed

@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

🧹 Nitpick comments (1)
Dockerfile (1)

529-533: Run the Docker-focused E2E subset before merge.

This updates baked runtime behavior (preload packaging + healthcheck liveness fallback), so validate it with the recommended nightly-e2e job subset on this branch.

As per coding guidelines, Dockerfile changes are only reliably validated with real container build/runtime and the listed E2E suites.

Also applies to: 1091-1106

🤖 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 `@Dockerfile` around lines 529 - 533, This change touches Dockerfile runtime
packaging (the COPY of preload JS files) and liveness behavior; before merging,
run the Docker-focused E2E subset (the nightly-e2e job subset) against this
branch to validate container build and runtime behavior—specifically confirm the
preloads are present in the container and the healthcheck liveness fallback
works—then only merge once those E2E runs pass.

Source: Coding guidelines

🤖 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/messaging/compiler/workflow-planner.ts`:
- Around line 107-111: The three builders buildChannelStopPlanFromSandboxEntry,
buildChannelStartPlanFromSandboxEntry, and buildRebuildPlanFromSandboxEntry
currently call setPlanChannelDisabled / setPlanDisabledChannels but do not
filter plan.runtimeSetup, so hydrateDerivedSandboxMessagingPlanFields can keep
stale runtimeSetup entries; update those three functions to explicitly filter
plan.runtimeSetup after modifying disabledChannels (same approach used in
removePlanChannel) so runtimeSetup only contains entries for channels where
channel.active && !channel.disabled, or alternatively ensure the downstream
applier that consumes runtimeSetup.nodePreloads / envAliases / secretScans
always re-gates by channel.active && !channel.disabled; pick one fix and
implement it consistently (prefer adding the runtimeSetup filter in the three
builder functions to mirror removePlanChannel and avoid relying on downstream
behavior).

---

Nitpick comments:
In `@Dockerfile`:
- Around line 529-533: This change touches Dockerfile runtime packaging (the
COPY of preload JS files) and liveness behavior; before merging, run the
Docker-focused E2E subset (the nightly-e2e job subset) against this branch to
validate container build and runtime behavior—specifically confirm the preloads
are present in the container and the healthcheck liveness fallback works—then
only merge once those E2E runs pass.
🪄 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: f207dbbc-a632-4f30-ab2c-a5f222ac1fe4

📥 Commits

Reviewing files that changed from the base of the PR and between b99378a and 5c71c1f.

📒 Files selected for processing (91)
  • .github/workflows/e2e-vitest-scenarios.yaml
  • Dockerfile
  • ci/env-var-doc-allowlist.json
  • ci/test-file-size-budget.json
  • nemoclaw-blueprint/policies/presets/wechat.yaml
  • scripts/install.sh
  • scripts/nemoclaw-start.sh
  • src/lib/actions/sandbox/doctor.ts
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/actions/sandbox/snapshot.ts
  • src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts
  • src/lib/channel-runtime-status.ts
  • src/lib/credentials/store.ts
  • src/lib/host-qr-handlers.ts
  • src/lib/inference/nim.test.ts
  • src/lib/inventory/index.test.ts
  • src/lib/inventory/index.ts
  • src/lib/messaging-channel-config.test.ts
  • src/lib/messaging/applier/hook-phases.test.ts
  • src/lib/messaging/applier/hook-phases.ts
  • src/lib/messaging/applier/host-state-applier.ts
  • src/lib/messaging/applier/setup-applier.test.ts
  • src/lib/messaging/applier/setup-applier.ts
  • src/lib/messaging/channels/discord/hooks/index.ts
  • src/lib/messaging/channels/discord/hooks/openclaw-bridge-health.ts
  • src/lib/messaging/channels/discord/manifest.ts
  • src/lib/messaging/channels/manifests.test.ts
  • src/lib/messaging/channels/metadata.test.ts
  • src/lib/messaging/channels/metadata.ts
  • src/lib/messaging/channels/openclaw-bridge-health.test.ts
  • src/lib/messaging/channels/openclaw-bridge-health.ts
  • src/lib/messaging/channels/slack/hooks/index.ts
  • src/lib/messaging/channels/slack/hooks/openclaw-bridge-health.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.test.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-status.test.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-status.ts
  • src/lib/messaging/channels/slack/manifest.ts
  • src/lib/messaging/channels/slack/runtime/slack-channel-guard.js
  • src/lib/messaging/channels/telegram/hooks/gateway-conflict-status.test.ts
  • src/lib/messaging/channels/telegram/hooks/gateway-conflict-status.ts
  • src/lib/messaging/channels/telegram/hooks/get-me-reachability.ts
  • src/lib/messaging/channels/telegram/hooks/index.ts
  • src/lib/messaging/channels/telegram/hooks/openclaw-bridge-health.ts
  • src/lib/messaging/channels/telegram/manifest.ts
  • src/lib/messaging/channels/telegram/runtime/telegram-diagnostics.js
  • src/lib/messaging/channels/wechat/hooks/host-qr-login-runtime.ts
  • src/lib/messaging/channels/wechat/login.test.ts
  • src/lib/messaging/channels/wechat/login.ts
  • src/lib/messaging/channels/wechat/manifest.ts
  • src/lib/messaging/channels/wechat/qr.test.ts
  • src/lib/messaging/channels/wechat/qr.ts
  • src/lib/messaging/channels/wechat/runtime/wechat-diagnostics.js
  • src/lib/messaging/channels/whatsapp/manifest.ts
  • src/lib/messaging/channels/whatsapp/runtime/whatsapp-qr-compact.js
  • src/lib/messaging/compiler/engines/build-step-engine.ts
  • src/lib/messaging/compiler/engines/health-check-engine.ts
  • src/lib/messaging/compiler/engines/runtime-setup-engine.ts
  • src/lib/messaging/compiler/manifest-compiler.test.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/messaging/hooks/builtins.ts
  • src/lib/messaging/hooks/errors.ts
  • src/lib/messaging/hooks/hook-runner.test.ts
  • src/lib/messaging/hooks/hook-runner.ts
  • src/lib/messaging/hooks/index.ts
  • src/lib/messaging/index.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/messaging/persistence.ts
  • src/lib/messaging/plan-validation.test.ts
  • src/lib/messaging/plan-validation.ts
  • src/lib/onboard.ts
  • src/lib/onboard/docker-gpu-patch-wsl.test.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/onboard/machine/core-flow-phases.test.ts
  • src/lib/onboard/messaging-channel-setup.test.ts
  • src/lib/onboard/messaging-conflict-guard.test.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • src/lib/onboard/policy-presets.ts
  • src/lib/onboard/sandbox-build-patch-config.test.ts
  • src/lib/onboard/sandbox-build-patch-config.ts
  • src/lib/onboard/sandbox-create-plan.ts
  • src/lib/policy/index.ts
  • src/lib/sandbox/channels.test.ts
  • src/lib/sandbox/channels.ts
  • src/lib/security/redact.ts
  • src/lib/state/onboard-session.test.ts
  • src/lib/status-command-deps.test.ts
  • src/lib/status-command-deps.ts
💤 Files with no reviewable changes (12)
  • .github/workflows/e2e-vitest-scenarios.yaml
  • src/lib/host-qr-handlers.ts
  • src/lib/sandbox/channels.test.ts
  • src/lib/state/onboard-session.test.ts
  • src/lib/onboard/sandbox-create-plan.ts
  • src/lib/onboard/sandbox-build-patch-config.ts
  • src/lib/security/redact.ts
  • src/lib/status-command-deps.ts
  • src/lib/sandbox/channels.ts
  • src/lib/status-command-deps.test.ts
  • src/lib/policy/index.ts
  • src/lib/onboard/sandbox-build-patch-config.test.ts
✅ Files skipped from review due to trivial changes (9)
  • ci/env-var-doc-allowlist.json
  • nemoclaw-blueprint/policies/presets/wechat.yaml
  • src/lib/messaging/channels/telegram/hooks/index.ts
  • src/lib/messaging/hooks/index.ts
  • src/lib/messaging/channels/slack/hooks/openclaw-bridge-health.ts
  • src/lib/messaging/channels/wechat/login.test.ts
  • src/lib/messaging/channels/wechat/qr.ts
  • scripts/install.sh
  • src/lib/messaging/channels/wechat/qr.test.ts
🚧 Files skipped from review as they are similar to previous changes (18)
  • src/lib/credentials/store.ts
  • src/lib/onboard/messaging-conflict-guard.test.ts
  • src/lib/messaging/index.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/actions/sandbox/snapshot.ts
  • src/lib/inventory/index.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/onboard.ts
  • src/lib/messaging/plan-validation.test.ts
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • src/lib/messaging/applier/setup-applier.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.test.ts
  • src/lib/actions/sandbox/doctor.ts
  • src/lib/inventory/index.test.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.ts
  • src/lib/onboard/policy-presets.ts
  • scripts/nemoclaw-start.sh

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🧹 Nitpick comments (1)
Dockerfile (1)

529-533: Run the Docker-focused E2E subset before merge.

This updates baked runtime behavior (preload packaging + healthcheck liveness fallback), so validate it with the recommended nightly-e2e job subset on this branch.

As per coding guidelines, Dockerfile changes are only reliably validated with real container build/runtime and the listed E2E suites.

Also applies to: 1091-1106

🤖 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 `@Dockerfile` around lines 529 - 533, This change touches Dockerfile runtime
packaging (the COPY of preload JS files) and liveness behavior; before merging,
run the Docker-focused E2E subset (the nightly-e2e job subset) against this
branch to validate container build and runtime behavior—specifically confirm the
preloads are present in the container and the healthcheck liveness fallback
works—then only merge once those E2E runs pass.

Source: Coding guidelines

🤖 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/messaging/compiler/workflow-planner.ts`:
- Around line 107-111: The three builders buildChannelStopPlanFromSandboxEntry,
buildChannelStartPlanFromSandboxEntry, and buildRebuildPlanFromSandboxEntry
currently call setPlanChannelDisabled / setPlanDisabledChannels but do not
filter plan.runtimeSetup, so hydrateDerivedSandboxMessagingPlanFields can keep
stale runtimeSetup entries; update those three functions to explicitly filter
plan.runtimeSetup after modifying disabledChannels (same approach used in
removePlanChannel) so runtimeSetup only contains entries for channels where
channel.active && !channel.disabled, or alternatively ensure the downstream
applier that consumes runtimeSetup.nodePreloads / envAliases / secretScans
always re-gates by channel.active && !channel.disabled; pick one fix and
implement it consistently (prefer adding the runtimeSetup filter in the three
builder functions to mirror removePlanChannel and avoid relying on downstream
behavior).

---

Nitpick comments:
In `@Dockerfile`:
- Around line 529-533: This change touches Dockerfile runtime packaging (the
COPY of preload JS files) and liveness behavior; before merging, run the
Docker-focused E2E subset (the nightly-e2e job subset) against this branch to
validate container build and runtime behavior—specifically confirm the preloads
are present in the container and the healthcheck liveness fallback works—then
only merge once those E2E runs pass.
🪄 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: f207dbbc-a632-4f30-ab2c-a5f222ac1fe4

📥 Commits

Reviewing files that changed from the base of the PR and between b99378a and 5c71c1f.

📒 Files selected for processing (91)
  • .github/workflows/e2e-vitest-scenarios.yaml
  • Dockerfile
  • ci/env-var-doc-allowlist.json
  • ci/test-file-size-budget.json
  • nemoclaw-blueprint/policies/presets/wechat.yaml
  • scripts/install.sh
  • scripts/nemoclaw-start.sh
  • src/lib/actions/sandbox/doctor.ts
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/actions/sandbox/snapshot.ts
  • src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts
  • src/lib/channel-runtime-status.ts
  • src/lib/credentials/store.ts
  • src/lib/host-qr-handlers.ts
  • src/lib/inference/nim.test.ts
  • src/lib/inventory/index.test.ts
  • src/lib/inventory/index.ts
  • src/lib/messaging-channel-config.test.ts
  • src/lib/messaging/applier/hook-phases.test.ts
  • src/lib/messaging/applier/hook-phases.ts
  • src/lib/messaging/applier/host-state-applier.ts
  • src/lib/messaging/applier/setup-applier.test.ts
  • src/lib/messaging/applier/setup-applier.ts
  • src/lib/messaging/channels/discord/hooks/index.ts
  • src/lib/messaging/channels/discord/hooks/openclaw-bridge-health.ts
  • src/lib/messaging/channels/discord/manifest.ts
  • src/lib/messaging/channels/manifests.test.ts
  • src/lib/messaging/channels/metadata.test.ts
  • src/lib/messaging/channels/metadata.ts
  • src/lib/messaging/channels/openclaw-bridge-health.test.ts
  • src/lib/messaging/channels/openclaw-bridge-health.ts
  • src/lib/messaging/channels/slack/hooks/index.ts
  • src/lib/messaging/channels/slack/hooks/openclaw-bridge-health.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.test.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-status.test.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-status.ts
  • src/lib/messaging/channels/slack/manifest.ts
  • src/lib/messaging/channels/slack/runtime/slack-channel-guard.js
  • src/lib/messaging/channels/telegram/hooks/gateway-conflict-status.test.ts
  • src/lib/messaging/channels/telegram/hooks/gateway-conflict-status.ts
  • src/lib/messaging/channels/telegram/hooks/get-me-reachability.ts
  • src/lib/messaging/channels/telegram/hooks/index.ts
  • src/lib/messaging/channels/telegram/hooks/openclaw-bridge-health.ts
  • src/lib/messaging/channels/telegram/manifest.ts
  • src/lib/messaging/channels/telegram/runtime/telegram-diagnostics.js
  • src/lib/messaging/channels/wechat/hooks/host-qr-login-runtime.ts
  • src/lib/messaging/channels/wechat/login.test.ts
  • src/lib/messaging/channels/wechat/login.ts
  • src/lib/messaging/channels/wechat/manifest.ts
  • src/lib/messaging/channels/wechat/qr.test.ts
  • src/lib/messaging/channels/wechat/qr.ts
  • src/lib/messaging/channels/wechat/runtime/wechat-diagnostics.js
  • src/lib/messaging/channels/whatsapp/manifest.ts
  • src/lib/messaging/channels/whatsapp/runtime/whatsapp-qr-compact.js
  • src/lib/messaging/compiler/engines/build-step-engine.ts
  • src/lib/messaging/compiler/engines/health-check-engine.ts
  • src/lib/messaging/compiler/engines/runtime-setup-engine.ts
  • src/lib/messaging/compiler/manifest-compiler.test.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/messaging/hooks/builtins.ts
  • src/lib/messaging/hooks/errors.ts
  • src/lib/messaging/hooks/hook-runner.test.ts
  • src/lib/messaging/hooks/hook-runner.ts
  • src/lib/messaging/hooks/index.ts
  • src/lib/messaging/index.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/messaging/persistence.ts
  • src/lib/messaging/plan-validation.test.ts
  • src/lib/messaging/plan-validation.ts
  • src/lib/onboard.ts
  • src/lib/onboard/docker-gpu-patch-wsl.test.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/onboard/machine/core-flow-phases.test.ts
  • src/lib/onboard/messaging-channel-setup.test.ts
  • src/lib/onboard/messaging-conflict-guard.test.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • src/lib/onboard/policy-presets.ts
  • src/lib/onboard/sandbox-build-patch-config.test.ts
  • src/lib/onboard/sandbox-build-patch-config.ts
  • src/lib/onboard/sandbox-create-plan.ts
  • src/lib/policy/index.ts
  • src/lib/sandbox/channels.test.ts
  • src/lib/sandbox/channels.ts
  • src/lib/security/redact.ts
  • src/lib/state/onboard-session.test.ts
  • src/lib/status-command-deps.test.ts
  • src/lib/status-command-deps.ts
💤 Files with no reviewable changes (12)
  • .github/workflows/e2e-vitest-scenarios.yaml
  • src/lib/host-qr-handlers.ts
  • src/lib/sandbox/channels.test.ts
  • src/lib/state/onboard-session.test.ts
  • src/lib/onboard/sandbox-create-plan.ts
  • src/lib/onboard/sandbox-build-patch-config.ts
  • src/lib/security/redact.ts
  • src/lib/status-command-deps.ts
  • src/lib/sandbox/channels.ts
  • src/lib/status-command-deps.test.ts
  • src/lib/policy/index.ts
  • src/lib/onboard/sandbox-build-patch-config.test.ts
✅ Files skipped from review due to trivial changes (9)
  • ci/env-var-doc-allowlist.json
  • nemoclaw-blueprint/policies/presets/wechat.yaml
  • src/lib/messaging/channels/telegram/hooks/index.ts
  • src/lib/messaging/hooks/index.ts
  • src/lib/messaging/channels/slack/hooks/openclaw-bridge-health.ts
  • src/lib/messaging/channels/wechat/login.test.ts
  • src/lib/messaging/channels/wechat/qr.ts
  • scripts/install.sh
  • src/lib/messaging/channels/wechat/qr.test.ts
🚧 Files skipped from review as they are similar to previous changes (18)
  • src/lib/credentials/store.ts
  • src/lib/onboard/messaging-conflict-guard.test.ts
  • src/lib/messaging/index.ts
  • src/lib/onboard/docker-gpu-patch.ts
  • src/lib/actions/sandbox/snapshot.ts
  • src/lib/inventory/index.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/onboard.ts
  • src/lib/messaging/plan-validation.test.ts
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/onboard/messaging-conflict-guard.ts
  • src/lib/messaging/applier/setup-applier.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.test.ts
  • src/lib/actions/sandbox/doctor.ts
  • src/lib/inventory/index.test.ts
  • src/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.ts
  • src/lib/onboard/policy-presets.ts
  • scripts/nemoclaw-start.sh
🛑 Comments failed to post (1)
src/lib/messaging/compiler/workflow-planner.ts (1)

107-111: ⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect runtimeSetup handling across planner/applier paths
rg -n --type=ts -C4 'runtimeSetup|nodePreloads|envAliases|secretScans|setPlanChannelDisabled|setPlanDisabledChannels|buildChannelStopPlanFromSandboxEntry|buildRebuildPlanFromSandboxEntry' src/lib

# Inspect where runtime setup is actually applied/executed
rg -n --type=ts -C4 'apply.*runtime|runtime.*apply|nodePreload|envAlias|secretScan' src/lib/messaging src/lib/onboard src/lib/actions

Repository: NVIDIA/NemoClaw

Length of output: 50371


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the exact implementations around setPlanChannelDisabled / setPlanDisabledChannels
sed -n '70,160p' src/lib/messaging/compiler/workflow-planner.ts
sed -n '260,460p' src/lib/messaging/compiler/workflow-planner.ts

# Show where runtimeSetup is consumed in the applier
rg -n --type=ts 'runtimeSetup' src/lib/messaging/applier -S
sed -n '1,260p' src/lib/messaging/applier/setup-applier.ts
sed -n '260,520p' src/lib/messaging/applier/setup-applier.ts

# Show runtime-setup engine gating logic
sed -n '1,120p' src/lib/messaging/compiler/engines/runtime-setup-engine.ts

# Show how plans are applied on stop/start/rebuild actions
sed -n '700,820p' src/lib/actions/sandbox/policy-channel.ts
sed -n '200,320p' src/lib/actions/sandbox/rebuild.ts

# Show host-state applier merge behavior (may still not filter)
sed -n '1,200p' src/lib/messaging/applier/host-state-applier.ts

Repository: NVIDIA/NemoClaw

Length of output: 34283


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find direct consumption of runtimeSetup fields (not just validation/merge)
rg -n --type=ts 'runtimeSetup\.|nodePreloads|envAliases|secretScans' src/lib/messaging/applier src/lib/messaging/compiler/engines src/lib/messaging/compiler src/lib/actions | head -n 200

# Find where runtimeSetup is fed into something that writes to host / applies hooks
rg -n --type=ts 'nodePreloads|envAliases|secretScans' src/lib/messaging/applier src/lib/messaging/compiler | head -n 200

# Find the runtime-setup-engine entrypoint usage
rg -n --type=ts 'runtime-setup-engine' src/lib/messaging src/lib/actions

# Show runtime-setup-engine integration file(s)
rg -n --type=ts 'planRuntimeSetup\\(|runtimeSetup' src/lib/messaging/compiler | head -n 200

Repository: NVIDIA/NemoClaw

Length of output: 8093


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Fix: find all actual reads of runtimeSetup in messaging code
rg -n --type=ts 'runtimeSetup' src/lib/messaging | head -n 200

# Find concrete consumption of runtimeSetup arrays (reads, not just validation types)
rg -n --type=ts '\.runtimeSetup\.(nodePreloads|envAliases|secretScans)' src/lib/messaging src/lib/actions | head -n 200

# Search for direct iteration/consumption without dot access
rg -n --type=ts '(for \\(.*nodePreloads|map\\(.*nodePreloads|envAliases|secretScans)' src/lib/messaging src/lib/actions | head -n 200

# Inspect persistence: where derived fields might be hydrated/applied
rg -n --type=ts 'function hydrateDerivedSandboxMessagingPlanFields|hydrateDerivedSandboxMessagingPlanFields' src/lib/messaging/persistence.ts
sed -n '1,240p' src/lib/messaging/persistence.ts
sed -n '240,520p' src/lib/messaging/persistence.ts

Repository: NVIDIA/NemoClaw

Length of output: 2321


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate hydration function and planRuntimeSetup usage in persistence.ts
rg -n --type=ts 'function hydrateDerivedSandboxMessagingPlanFields|hydrateDerivedSandboxMessagingPlanFields|planRuntimeSetup' src/lib/messaging/persistence.ts

# Print relevant sections around those lines
# (Use sed with line ranges estimated by the found line numbers)
# We'll capture the line numbers first, then sed accordingly.
LINES=$(rg -n --type=ts 'function hydrateDerivedSandboxMessagingPlanFields|hydrateDerivedSandboxMessagingPlanFields|planRuntimeSetup' src/lib/messaging/persistence.ts | cut -d: -f1 | tr '\n' ' ')
echo "LineNumbers: $LINES"

# Get around the first hydration function occurrence
line=$(rg -n --type=ts 'function hydrateDerivedSandboxMessagingPlanFields' src/lib/messaging/persistence.ts | head -n1 | cut -d: -f1)
start=$((line-80)); end=$((line+200))
sed -n "${start},${end}p" src/lib/messaging/persistence.ts

# Also inspect around normalize/derive runtime setup (look for runtimeSetup: planRuntimeSetup or similar)
rg -n --type=ts 'runtimeSetup:\s*planRuntimeSetup|runtimeSetup\s*=\s*planRuntimeSetup' src/lib/messaging/persistence.ts || true

Repository: NVIDIA/NemoClaw

Length of output: 11095


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate hydration function and any planRuntimeSetup usage in persistence.ts
rg -n --type=ts 'function hydrateDerivedSandboxMessagingPlanFields|hydrateDerivedSandboxMessagingPlanFields|planRuntimeSetup' src/lib/messaging/persistence.ts

# Dump the region around hydrateDerivedSandboxMessagingPlanFields
line=$(rg -n --type=ts 'function hydrateDerivedSandboxMessagingPlanFields' src/lib/messaging/persistence.ts | head -n1 | cut -d: -f1)
start=$((line-80)); end=$((line+220))
sed -n "${start},${end}p" src/lib/messaging/persistence.ts

# Dump any inline runtimeSetup derivation patterns if present
rg -n --type=ts 'runtimeSetup:\s*planRuntimeSetup|runtimeSetup\s*=\s*planRuntimeSetup' src/lib/messaging/persistence.ts || true

Repository: NVIDIA/NemoClaw

Length of output: 11841


Fix runtimeSetup filtering for stop/start/rebuild (or ensure applier recomputes/gates).

buildChannelStopPlanFromSandboxEntry, buildChannelStartPlanFromSandboxEntry, and buildRebuildPlanFromSandboxEntry only update channels/disabledChannels (via setPlanChannelDisabled / setPlanDisabledChannels) and do not filter plan.runtimeSetup. Meanwhile, hydrateDerivedSandboxMessagingPlanFields() keeps an existing plan.runtimeSetup when it has any entries (runtimeSetupHasEntries(plan.runtimeSetup)), so it will not recompute runtimeSetup from channel.active && !channel.disabled in that case. If host-side setup/policy application consumes plan.runtimeSetup entries without re-gating by channel state, disabled channels may still contribute node preloads/env aliases/secret scans.

Add explicit runtimeSetup filtering for stop/start/rebuild (like removePlanChannel does), or ensure the code path that applies runtimeSetup.nodePreloads/envAliases/secretScans filters them to only channels where channel.active && !channel.disabled.

🤖 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/messaging/compiler/workflow-planner.ts` around lines 107 - 111, The
three builders buildChannelStopPlanFromSandboxEntry,
buildChannelStartPlanFromSandboxEntry, and buildRebuildPlanFromSandboxEntry
currently call setPlanChannelDisabled / setPlanDisabledChannels but do not
filter plan.runtimeSetup, so hydrateDerivedSandboxMessagingPlanFields can keep
stale runtimeSetup entries; update those three functions to explicitly filter
plan.runtimeSetup after modifying disabledChannels (same approach used in
removePlanChannel) so runtimeSetup only contains entries for channels where
channel.active && !channel.disabled, or alternatively ensure the downstream
applier that consumes runtimeSetup.nodePreloads / envAliases / secretScans
always re-gates by channel.active && !channel.disabled; pick one fix and
implement it consistently (prefer adding the runtimeSetup filter in the three
builder functions to mirror removePlanChannel and avoid relying on downstream
behavior).

…annel-manifest-stragglers

# Conflicts:
#	ci/test-file-size-budget.json
@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 14, 2026

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/messaging/channels/slack/runtime/slack-channel-guard.js (1)

1-247: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pipeline failure: CI blocks .js source files.

The CI reports this PR adds a JavaScript source file, which violates the repo policy requiring TypeScript for new Node.js code.

However, this file is a runtime preload (nodePreloads in the Slack manifest) that gets injected via NODE_OPTIONS --require before the TypeScript runtime is available. Runtime preloads often need to be plain JavaScript.

Consider one of:

  1. Add this path to the CI allowlist if runtime preloads are a legitimate exception
  2. Convert to TypeScript with a build step that emits this .js file to a dist location, then update the manifest's module reference
🤖 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/messaging/channels/slack/runtime/slack-channel-guard.js` around lines
1 - 247, The CI pipeline is rejecting the slack-channel-guard.js file because it
violates the TypeScript requirement for Node.js code. However, this file is a
legitimate exception since it is a runtime preload injected via NODE_OPTIONS
--require before the TypeScript runtime is available. Update the CI allowlist or
policy configuration to exclude runtime preload files (specifically the
slack-channel-guard.js preload and similar preload patterns) from the TypeScript
requirement, or document this path as an approved exception for Node.js preload
scripts that must remain as plain JavaScript.

Source: Pipeline failures

🧹 Nitpick comments (1)
Dockerfile (1)

651-651: Validate the runtime plan artifact bakes correctly with E2E tests.

The runtime-setup phase now bakes messaging metadata (nodePreloads, envAliases, secretScans) into the container image for startup consumption, and the Slack deny-feedback behavior has migrated from a build-time patch to a runtime preload. Per coding guidelines, Dockerfile layer ordering and baked config changes require validation with a real container build.

Run the recommended E2E tests before merge, with particular attention to openclaw-tui-chat-correlation-e2e since it validates that the baked OpenClaw chat send patch preserves user/assistant turn correlation—and the Slack deny-feedback behavior is now implemented as a runtime preload rather than a build-time patch.

To execute:

gh workflow run nightly-e2e.yaml --ref <your-branch> -f jobs=cloud-e2e,sandbox-survival-e2e,hermes-e2e,rebuild-openclaw-e2e,openclaw-tui-chat-correlation-e2e
🤖 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 `@Dockerfile` at line 651, The Dockerfile runtime-setup phase now bakes
messaging metadata into the container and has migrated the Slack deny-feedback
behavior from a build-time patch to a runtime preload. Before merging, this
configuration change must be validated with E2E tests. Execute the nightly E2E
workflow with the specified job list (cloud-e2e, sandbox-survival-e2e,
hermes-e2e, rebuild-openclaw-e2e, openclaw-tui-chat-correlation-e2e) on your
branch to confirm the baked OpenClaw chat send patch preserves user/assistant
turn correlation and the runtime preload implementation of Slack deny-feedback
behavior functions correctly in a real container build.

Source: Coding guidelines

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

Outside diff comments:
In `@src/lib/messaging/channels/slack/runtime/slack-channel-guard.js`:
- Around line 1-247: The CI pipeline is rejecting the slack-channel-guard.js
file because it violates the TypeScript requirement for Node.js code. However,
this file is a legitimate exception since it is a runtime preload injected via
NODE_OPTIONS --require before the TypeScript runtime is available. Update the CI
allowlist or policy configuration to exclude runtime preload files (specifically
the slack-channel-guard.js preload and similar preload patterns) from the
TypeScript requirement, or document this path as an approved exception for
Node.js preload scripts that must remain as plain JavaScript.

---

Nitpick comments:
In `@Dockerfile`:
- Line 651: The Dockerfile runtime-setup phase now bakes messaging metadata into
the container and has migrated the Slack deny-feedback behavior from a
build-time patch to a runtime preload. Before merging, this configuration change
must be validated with E2E tests. Execute the nightly E2E workflow with the
specified job list (cloud-e2e, sandbox-survival-e2e, hermes-e2e,
rebuild-openclaw-e2e, openclaw-tui-chat-correlation-e2e) on your branch to
confirm the baked OpenClaw chat send patch preserves user/assistant turn
correlation and the runtime preload implementation of Slack deny-feedback
behavior functions correctly in a real container build.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 401a45fa-0fd9-481b-a730-0fdc883cf6f5

📥 Commits

Reviewing files that changed from the base of the PR and between f7c0b68 and 3b46a32.

📒 Files selected for processing (16)
  • Dockerfile
  • scripts/patch-openclaw-slack-deny-feedback.mts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/messaging/channels/manifests.test.ts
  • src/lib/messaging/channels/slack/runtime/slack-channel-guard.js
  • src/lib/messaging/channels/wechat/hooks/host-qr-login-runtime.ts
  • src/lib/messaging/channels/wechat/hooks/implementations.test.ts
  • src/lib/messaging/channels/wechat/hooks/seed-openclaw-account.ts
  • src/lib/messaging/channels/wechat/manifest.ts
  • src/lib/messaging/channels/wechat/qr.ts
  • src/lib/messaging/plan-validation.test.ts
  • src/lib/messaging/plan-validation.ts
  • src/lib/sandbox/build-context.ts
  • test/messaging-build-applier.test.ts
  • test/openclaw-slack-deny-feedback-patch.test.ts
  • test/sandbox-build-context.test.ts
💤 Files with no reviewable changes (3)
  • scripts/patch-openclaw-slack-deny-feedback.mts
  • test/sandbox-build-context.test.ts
  • src/lib/sandbox/build-context.ts
✅ Files skipped from review due to trivial changes (1)
  • src/lib/messaging/channels/wechat/qr.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/messaging/channels/wechat/manifest.ts
  • src/lib/messaging/plan-validation.test.ts
  • src/lib/messaging/plan-validation.ts

Comment thread src/lib/messaging/channels/telegram/runtime/telegram-diagnostics.ts Fixed
Comment thread src/lib/messaging/channels/telegram/runtime/telegram-diagnostics.ts Fixed

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/e2e-scenario/live/whatsapp-qr-compact.test.ts (1)

188-191: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing --experimental-strip-types for TypeScript preload.

The test invokes node --require ${PRELOAD} where PRELOAD is a .ts file. Node.js will not load a .ts extension file without --experimental-strip-types, even if the file content is valid JavaScript. The test will fail with:

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"
Proposed fix
       const patched = await runCommand("node", ["probe.mjs"], {
         cwd: workdir,
-        env: { NODE_OPTIONS: `--require ${PRELOAD}` },
+        env: { NODE_OPTIONS: `--experimental-strip-types --require ${PRELOAD}` },
         timeoutMs: PROBE_TIMEOUT_MS,
       });
🤖 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/e2e-scenario/live/whatsapp-qr-compact.test.ts` around lines 188 - 191,
The runCommand invocation for probe.mjs is attempting to require a TypeScript
file via NODE_OPTIONS without the --experimental-strip-types flag, which will
cause Node.js to fail with an unknown file extension error. Add the
--experimental-strip-types flag to the NODE_OPTIONS environment variable in the
runCommand call so that Node.js can properly load and parse the TypeScript
preload file specified by PRELOAD.
🤖 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/messaging/channels/telegram/runtime/telegram-diagnostics.ts`:
- Line 1: Remove the `// `@ts-nocheck`` directive from the top of both diagnostic
runtime modules to restore TypeScript type-checking compliance. In
src/lib/messaging/channels/telegram/runtime/telegram-diagnostics.ts at line 1,
delete the `@ts-nocheck` comment and ensure all process augmentation and wrapper
code has proper type annotations. Similarly, in
src/lib/messaging/channels/wechat/runtime/wechat-diagnostics.ts at line 1,
remove the `@ts-nocheck` comment and add proper TypeScript typing for any
process augmentation or wrappers. This ensures both files comply with repository
rules requiring typed validation via tsconfig-backed compilation for code under
src/lib.

---

Outside diff comments:
In `@test/e2e-scenario/live/whatsapp-qr-compact.test.ts`:
- Around line 188-191: The runCommand invocation for probe.mjs is attempting to
require a TypeScript file via NODE_OPTIONS without the
--experimental-strip-types flag, which will cause Node.js to fail with an
unknown file extension error. Add the --experimental-strip-types flag to the
NODE_OPTIONS environment variable in the runCommand call so that Node.js can
properly load and parse the TypeScript preload file specified by PRELOAD.
🪄 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: 5ba6d266-eb75-4d2d-98c3-d5d21041cb98

📥 Commits

Reviewing files that changed from the base of the PR and between 3b46a32 and 848c9ec.

📒 Files selected for processing (13)
  • Dockerfile
  • src/lib/messaging/channels/slack/runtime/slack-channel-guard.ts
  • src/lib/messaging/channels/telegram/runtime/telegram-diagnostics.ts
  • src/lib/messaging/channels/wechat/runtime/wechat-diagnostics.ts
  • src/lib/messaging/channels/whatsapp/runtime/whatsapp-qr-compact.ts
  • test/e2e-scenario/live/whatsapp-qr-compact.test.ts
  • test/local-slack-auth-test.sh
  • test/nemoclaw-start-telegram-runtime.test.ts
  • test/nemoclaw-start.test.ts
  • test/openclaw-slack-deny-feedback-patch.test.ts
  • test/telegram-diagnostics.test.ts
  • test/wechat-diagnostics.test.ts
  • test/whatsapp-qr-compact.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/openclaw-slack-deny-feedback-patch.test.ts
  • test/nemoclaw-start.test.ts

Comment thread src/lib/messaging/channels/telegram/runtime/telegram-diagnostics.ts Outdated
@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 15, 2026
@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 27524152636
Target ref: refactor/messaging-channel-manifest-stragglers
Requested jobs: messaging-providers-e2e,messaging-compatible-endpoint-e2e
Summary: 0 passed, 2 failed, 0 cancelled, 0 skipped

Job Result
messaging-compatible-endpoint-e2e ❌ failure
messaging-providers-e2e ❌ failure

Failed jobs: messaging-compatible-endpoint-e2e, messaging-providers-e2e. Check run artifacts for logs.

@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 27525173397
Target ref: refactor/messaging-channel-manifest-stragglers
Requested jobs: messaging-providers-e2e,messaging-compatible-endpoint-e2e
Summary: 2 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
messaging-compatible-endpoint-e2e ✅ success
messaging-providers-e2e ✅ success

@sandl99 sandl99 added v0.0.65 Release target v0.0.66 Release target and removed v0.0.65 Release target labels Jun 15, 2026
@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 15, 2026
@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 27525651361
Target ref: refactor/messaging-channel-manifest-stragglers
Requested jobs: cloud-e2e,cloud-onboard-e2e,cloud-inference-e2e,cron-preflight-inference-local-e2e,agent-turn-latency-e2e,skill-agent-e2e,openclaw-skill-cli-e2e,docs-validation-e2e,messaging-providers-e2e,openclaw-slack-pairing-e2e,openclaw-tui-chat-correlation-e2e,issue-4434-tui-unreachable-inference-e2e,issue-3600-gpu-proof-optional-e2e,openclaw-discord-pairing-e2e,issue-4462-scope-upgrade-approval-e2e,issue-4462-gateway-pinned-approval-characterization-e2e,messaging-compatible-endpoint-e2e,sessions-agents-cli-e2e,channels-add-remove-e2e,channels-stop-start-openclaw-e2e,channels-stop-start-hermes-e2e,brave-search-e2e,common-egress-agent-e2e,kimi-inference-compat-e2e,bedrock-runtime-compatible-anthropic-e2e,token-rotation-e2e,sandbox-survival-e2e,issue-2478-crash-loop-recovery-e2e,hermes-e2e,hermes-dashboard-e2e,hermes-root-entrypoint-smoke-e2e,hermes-secret-boundary-e2e,openclaw-onboard-security-posture-e2e,hermes-onboard-security-posture-e2e,hermes-inference-switch-e2e,hermes-anthropic-inference-switch-e2e,hermes-discord-e2e,hermes-slack-e2e,sandbox-operations-e2e,inference-routing-e2e,openclaw-inference-switch-e2e,openclaw-anthropic-inference-switch-e2e,network-policy-e2e,state-backup-restore-e2e,tunnel-lifecycle-e2e,diagnostics-e2e,credential-migration-e2e,snapshot-commands-e2e,shields-config-e2e,rebuild-openclaw-e2e,upgrade-stale-sandbox-e2e,openshell-gateway-upgrade-e2e,rebuild-hermes-e2e,rebuild-hermes-stale-base-e2e,double-onboard-e2e,onboard-repair-e2e,onboard-resume-e2e,onboard-negative-paths-e2e,runtime-overrides-e2e,credential-sanitization-e2e,telegram-injection-e2e,overlayfs-autofix-e2e,device-auth-health-e2e,launchable-smoke-e2e,gpu-e2e,gpu-double-onboard-e2e,concurrent-gateway-ports-e2e
Summary: 65 passed, 0 failed, 0 cancelled, 2 skipped

Job Result
agent-turn-latency-e2e ✅ success
bedrock-runtime-compatible-anthropic-e2e ✅ success
brave-search-e2e ✅ success
channels-add-remove-e2e ✅ success
channels-stop-start-hermes-e2e ✅ success
channels-stop-start-openclaw-e2e ✅ success
cloud-e2e ✅ success
cloud-inference-e2e ✅ success
cloud-onboard-e2e ✅ success
common-egress-agent-e2e ✅ success
concurrent-gateway-ports-e2e ✅ success
credential-migration-e2e ✅ success
credential-sanitization-e2e ✅ success
cron-preflight-inference-local-e2e ✅ success
device-auth-health-e2e ✅ success
diagnostics-e2e ✅ success
docs-validation-e2e ✅ success
double-onboard-e2e ✅ success
gpu-double-onboard-e2e ⏭️ skipped
gpu-e2e ⏭️ skipped
hermes-anthropic-inference-switch-e2e ✅ success
hermes-dashboard-e2e ✅ success
hermes-discord-e2e ✅ success
hermes-e2e ✅ success
hermes-inference-switch-e2e ✅ success
hermes-onboard-security-posture-e2e ✅ success
hermes-root-entrypoint-smoke-e2e ✅ success
hermes-secret-boundary-e2e ✅ success
hermes-slack-e2e ✅ success
inference-routing-e2e ✅ success
issue-2478-crash-loop-recovery-e2e ✅ success
issue-3600-gpu-proof-optional-e2e ✅ success
issue-4434-tui-unreachable-inference-e2e ✅ success
issue-4462-gateway-pinned-approval-characterization-e2e ✅ success
issue-4462-scope-upgrade-approval-e2e ✅ success
kimi-inference-compat-e2e ✅ success
launchable-smoke-e2e ✅ success
messaging-compatible-endpoint-e2e ✅ success
messaging-providers-e2e ✅ success
network-policy-e2e ✅ success
onboard-negative-paths-e2e ✅ success
onboard-repair-e2e ✅ success
onboard-resume-e2e ✅ success
openclaw-anthropic-inference-switch-e2e ✅ success
openclaw-discord-pairing-e2e ✅ success
openclaw-inference-switch-e2e ✅ success
openclaw-onboard-security-posture-e2e ✅ success
openclaw-skill-cli-e2e ✅ success
openclaw-slack-pairing-e2e ✅ success
openclaw-tui-chat-correlation-e2e ✅ success
openshell-gateway-upgrade-e2e ✅ success
overlayfs-autofix-e2e ✅ success
rebuild-hermes-e2e ✅ success
rebuild-hermes-stale-base-e2e ✅ success
rebuild-openclaw-e2e ✅ success
runtime-overrides-e2e ✅ success
sandbox-operations-e2e ✅ success
sandbox-survival-e2e ✅ success
sessions-agents-cli-e2e ✅ success
shields-config-e2e ✅ success
skill-agent-e2e ✅ success
snapshot-commands-e2e ✅ success
state-backup-restore-e2e ✅ success
telegram-injection-e2e ✅ success
token-rotation-e2e ✅ success
tunnel-lifecycle-e2e ✅ success
upgrade-stale-sandbox-e2e ✅ success

@cv cv merged commit ff6cfde into main Jun 15, 2026
333 of 340 checks passed
@cv cv deleted the refactor/messaging-channel-manifest-stragglers branch June 15, 2026 15:28
@cv cv added the v0.0.65 Release target label Jun 15, 2026
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 refactor PR restructures code without intended behavior change v0.0.65 Release target v0.0.66 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 7: finish manifest channel migration

4 participants