Skip to content

fix(cli): make channels add atomic when policy preset is missing#4577

Open
laitingsheng wants to merge 8 commits into
mainfrom
fix-4548-channels-add-preset-atomicity
Open

fix(cli): make channels add atomic when policy preset is missing#4577
laitingsheng wants to merge 8 commits into
mainfrom
fix-4548-channels-add-preset-atomicity

Conversation

@laitingsheng
Copy link
Copy Markdown
Contributor

@laitingsheng laitingsheng commented May 31, 2026

Summary

nemoclaw <sandbox> channels add <channel> reached process.exit(0) and wrote the channel into sandboxes.json even when the matching policy preset YAML was missing on disk, leaving the sandbox advertising a bridge that had no network policy. The add flow now parses the preset YAML (file present and network_policies: section yields at least one entry via parsePresetPolicyKeys) before --dry-run returns, before snapshotting registry/credentials state, and before token acquisition, and rolls back the gateway/registry/credential mutations when the post-write preset application fails. Rollback is best-effort: gateway-side steps that fail (provider detach/delete, or re-upsert during a re-add restore) print a Rollback could not fully clean <surfaces> warning so the operator can clean up manually.

Related Issue

Fixes #4548

Changes

  • addSandboxChannel runs the policies.loadPreset(canonical) + policies.parsePresetPolicyKeys(...) preflight before --dry-run returns, before snapshotting registry/credentials state, and before token acquisition, so a missing, unloadable, or unparseable preset (no usable entries under network_policies:) exits non-zero with a restore-and-re-run hint on stderr without prompting the operator or contacting the gateway.
  • The non-QR branch applies the preset after applyChannelAddToGatewayAndRegistry. On apply failure the new rollbackChannelAdd helper handles two cases. A fresh add clears credentials then calls applyChannelRemoveToGatewayAndRegistry (best-effort, prints residual warning before returning). A failed re-add of an already-enabled channel restores the prior registry entry first (so a later gateway-upsert exit cannot orphan the channel), prints the gateway-providers residual warning, then restores on-disk credentials and best-effort re-upserts the prior bridge providers.
  • applyChannelRemoveToGatewayAndRegistry grew an optional { bestEffort: true } mode that downgrades each gateway-side process.exit(1) to a log-and-continue so the registry rollback finishes even when openshell detach or delete fails; returns { ok, residual }.
  • applyChannelPresetIfAvailable no longer short-circuits via policies.listPresets(); the filesystem scan conflated "channel has no preset" with "preset file missing on disk", which is what let the original bug pass silently.
  • Docs (docs/manage-sandboxes/messaging-channels.mdx, docs/reference/commands.mdx): describe the missing-or-unparseable-preset abort, the best-effort fresh-add rollback with explicit residual warning, the re-add restoration semantics, and narrow --dry-run to "validate channel name and matching policy preset without prompting for credentials, contacting the gateway, or rebuilding"; one sentence per line per docs style guide.
  • test/channels-add-preset.test.ts: added presetFileMissing, presetMissingNetworkPolicies, presetMalformedYaml fixture toggles plus regression tests covering each abort/rollback path (missing YAML for both telegram and whatsapp/QR, missing network_policies: section, malformed YAML body, applyPreset-after-write rollback, rollback resilience when openshell detach fails, prior-config restoration on a failed re-add, and registry restoration ordering when the re-upsert during re-add rollback itself throws); the source-of-truth test now parses every preset via parsePresetPolicyKeys instead of just checking file existence.

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: Tinson Lai tinsonl@nvidia.com

Summary by CodeRabbit

  • New Features

    • Added an exported helper to parse channel preset policy keys.
  • Bug Fixes

    • Channel adds now require a valid built-in network policy preset; missing/malformed presets abort early (exit code 1) before prompting or persisting credentials. If preset application fails after registry write, staged tokens are cleared, changes are rolled back, and residual gateway items are warned with guidance to restore the preset YAML and re-run.
  • Refactor

    • Rollback now performs best-effort cleanup and reports residuals instead of hard exiting.
  • Documentation

    • Updated guides and command reference to reflect preset requirement, rollback/credential behavior, residual warnings, and restore-and-retry instructions.
  • Tests

    • Added/updated tests for preset loading failures, apply-failure aborts, credential rollback, residual warnings, and preset coverage.

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 31, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1b912a90-8b6e-4e10-8a17-6a42e8a58ffd

📥 Commits

Reviewing files that changed from the base of the PR and between c123539 and 3b3c520.

📒 Files selected for processing (4)
  • docs/manage-sandboxes/messaging-channels.mdx
  • docs/reference/commands.mdx
  • src/lib/actions/sandbox/policy-channel.ts
  • test/channels-add-preset.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • docs/reference/commands.mdx
  • src/lib/actions/sandbox/policy-channel.ts
  • test/channels-add-preset.test.ts

📝 Walkthrough

Walkthrough

The CLI now requires the channel's built-in network policy preset to load and validates parsed network_policies before finalizing channel add. Missing/malformed presets or preset-apply failures abort with exit 1 and trigger credential/bridge/registry rollback; tests and docs updated accordingly.

Changes

Preset Application Prerequisite for Channel Add

Layer / File(s) Summary
Rollback helper refactor (best-effort and residual reporting)
src/lib/actions/sandbox/policy-channel.ts
applyChannelRemoveToGatewayAndRegistry now accepts { bestEffort?: boolean }, gates detach/delete on gateway reachability, collects residual cleanup items (e.g., "gateway-providers"), and returns { ok, residual }.
Preset load/check, snapshot, and abort on failure
src/lib/actions/sandbox/policy-channel.ts
addSandboxChannel preloads policies.loadPreset and validates parsed network_policies; missing/malformed preset causes process.exit(1) with a restore-and-re-run hint. For non-QR (token) flows, failed applyChannelPresetIfAvailable() clears staged tokens, snapshots prior registry/provider credential state, and triggers rollbackChannelAdd which either restores prior registry/provider credentials or removes the new bridge via the refactored removal helper (best-effort), warning on residuals, then exits 1.
Tests: harness flags, credential tracking, and negative-paths
test/channels-add-preset.test.ts
Test harness gains flags to simulate missing/malformed presets; credential store stubs record savedCredentialKeys and deletedCredentialKeys; new tests assert early aborts for missing/malformed presets (including QR-only WhatsApp), rollback sequencing when applyPreset fails (credential deletion and registry rollback), residual gateway-provider warnings on detach failures, and a source-of-truth test ensuring a preset YAML exists for every known channel.
Documentation: channels add behavior
docs/manage-sandboxes/messaging-channels.mdx, docs/reference/commands.mdx
Docs require the built-in network policy preset YAML for channels add, state the preset is applied before rebuild, and instruct restoring the preset YAML and re-running channels add when load/apply fails; document rollback that removes bridge providers, the messagingChannels registry entry, and persisted credentials and exits without prompting for rebuild.
Policy export
src/lib/policy/index.ts
Exports parsePresetPolicyKeys(presetContent) so callers can inspect preset keys (e.g., network_policies).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#4013: Modifies preset-application and policy preset sync logic overlapping src/lib/actions/sandbox/policy-channel.ts.
  • NVIDIA/NemoClaw#4001: Changes removal/teardown logic related to gateway/registry cleanup in the same module.
  • NVIDIA/NemoClaw#3984: Related to preset parsing and network_policies handling in the policy module.

Suggested labels

NemoClaw CLI, bug, enhancement: policy, v0.0.56

Suggested reviewers

  • ericksoa
  • cv
  • wscurran

Poem

🐇 I found a YAML where presets slept,
A channel half-configured, promises kept.
Restore the file, then run the add again,
Rollback clears crumbs and rights the train.
Hop, patch, retry — channels whole again.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary fix: enforcing atomicity of channel addition when the policy preset is missing, which is the core issue addressed in #4548.
Linked Issues check ✅ Passed The PR comprehensively addresses all coding requirements from #4548: validates preset presence/parseability before mutations, aborts with non-zero exit on missing/invalid presets, implements rollback on preset application failure, and updates documentation and tests accordingly.
Out of Scope Changes check ✅ Passed All changes directly support the atomicity fix: policy loading logic, rollback helpers, preset validation, documentation updates, and comprehensive test coverage for abort and rollback scenarios. No unrelated modifications detected.

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

✨ 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 fix-4548-channels-add-preset-atomicity

Warning

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

🔧 ESLint

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

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


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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 31, 2026

E2E Advisor Recommendation

Required E2E: channels-add-remove-e2e, messaging-providers-e2e
Optional E2E: channels-stop-start-e2e, network-policy-e2e

Dispatch hint: channels-add-remove-e2e,messaging-providers-e2e

Auto-dispatched E2E: channels-add-remove-e2e, messaging-providers-e2e via nightly-e2e.yaml at 3b3c520b07653471121e4a19838f32ea5ea62cfenightly run

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • channels-add-remove-e2e (high (~75 min timeout)): Directly covers the touched user flow: onboard without messaging, nemoclaw <sandbox> channels add telegram, provider registration, matching policy preset application before rebuild, Telegram egress through the L7 proxy, and channel remove cleanup.
  • messaging-providers-e2e (high (~75 min timeout)): Validates the full messaging provider/placeholder/L7-proxy chain for Telegram, Discord, Slack, WeChat, plus the QR-only WhatsApp channels add path whose preset preflight was changed in this PR.

Optional E2E

  • channels-stop-start-e2e (very high (~120 min timeout)): Useful adjacent coverage for all messaging channels across OpenClaw and Hermes, including policy-preset presence while channels are enabled and QR-only WhatsApp lifecycle behavior. Not required because the PR primarily changes add-time preset preflight/rollback, not stop/start.
  • network-policy-e2e (high): Broader confidence that policy presets, restricted egress, hot reload, and SSRF guardrails still behave correctly after changing channel/preset coupling. Optional because channel-specific preset application is covered more directly by channels-add-remove-e2e.

New E2E recommendations

  • channel-add rollback on policy apply failure (high): Existing E2E covers successful channel add/remove, but not the new failure path where provider registration and registry/credential writes have already happened and applyPreset then fails. A live CLI E2E should verify rollback leaves no enabled channel, no stale credential hash, no rebuild prompt, and emits residual gateway-provider guidance when cleanup cannot fully complete.
    • Suggested test: Add a channels-add-policy-rollback E2E that forces policy-add/preset apply failure after a Telegram provider upsert and asserts registry, credentials, providers, and rebuild prompt behavior.
  • missing or malformed channel preset preflight (medium): Unit tests cover missing/malformed YAML, but no live E2E currently proves channels add telegram and channels add whatsapp abort before token prompts, gateway contact, registry writes, or rebuild prompts when the matching preset YAML is absent or unparsable.
    • Suggested test: Add a channel-preset-preflight E2E that temporarily hides or corrupts a built-in channel preset in an isolated checkout and validates fail-fast behavior for one token-backed channel and WhatsApp.

Dispatch hint

  • Workflow: .github/workflows/nightly-e2e.yaml
  • jobs input: channels-add-remove-e2e,messaging-providers-e2e

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 31, 2026

E2E Scenario Advisor Recommendation

Required scenario E2E: ubuntu-repo-cloud-openclaw-token-rotation, ubuntu-repo-cloud-openclaw-telegram, ubuntu-repo-cloud-openclaw-slack
Optional scenario E2E: ubuntu-repo-cloud-openclaw-discord, ubuntu-repo-cloud-hermes-slack, ubuntu-repo-cloud-hermes-discord

Dispatch required scenario E2E:

  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-token-rotation
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-telegram
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-slack

Workflow run

Full scenario advisor summary

E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: medium

Required scenario E2E

  • ubuntu-repo-cloud-openclaw-token-rotation: Changes alter channels add re-add/token-rotation rollback behavior, credential hash restoration, and gateway provider cleanup; this is the closest scenario surface for messaging provider rotation semantics.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-token-rotation
  • ubuntu-repo-cloud-openclaw-telegram: Exercises the single-token OpenClaw messaging path and verifies Telegram provider wiring/configuration around the channel preset surface affected by policy-channel changes.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-telegram
  • ubuntu-repo-cloud-openclaw-slack: Exercises the multi-provider Slack messaging path, including the special slack app/provider naming surface touched by channel gateway registration and rollback logic.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-slack

Optional scenario E2E

  • ubuntu-repo-cloud-openclaw-discord: Adjacent single-token OpenClaw messaging channel using the same channel preset and gateway-provider add path; useful if broader messaging coverage is desired beyond Telegram.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-discord
  • ubuntu-repo-cloud-hermes-slack: Adjacent Hermes onboarding/profile coverage for Slack messaging on a different agent; optional because the primary changed helper path is covered on Ubuntu/OpenClaw.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes-slack
  • ubuntu-repo-cloud-hermes-discord: Adjacent Hermes onboarding/profile coverage for Discord messaging on a different agent; optional unless maintainers want cross-agent confidence for the channel/preset surface.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes-discord

Relevant changed files

  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/policy/index.ts

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 31, 2026

PR Review Advisor

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

Review findings

🛠️ Needs attention

  • Offset the policy-channel.ts monolith growth (src/lib/actions/sandbox/policy-channel.ts:365): This PR adds preset preflight, best-effort rollback, residual-state handling, and re-add recovery to an already-large sandbox action file. The deterministic drift check reports policy-channel.ts grew from 1230 to 1345 lines (+115), increasing maintenance risk in a high-risk gateway/policy/credential boundary.
    • Recommendation: Extract the new channel-add preflight and rollback behavior into a focused helper module, or offset the growth with nearby cleanup before merge.
    • Evidence: The diff adds bestEffort support to applyChannelRemoveToGatewayAndRegistry(), adds preset preflight in addSandboxChannel(), and adds rollbackChannelAdd(), while the file remains over 1300 lines.

🔎 Worth checking

  • Source-of-truth review needed: Best-effort channel-add rollback after post-write policy apply failure: 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: applyChannelRemoveToGatewayAndRegistry() accepts { bestEffort: true }; rollbackChannelAdd() calls it for fresh-add apply failure; token-backed add still mutates credentials/gateway/registry before applying the preset.
  • Source-of-truth review needed: Already-enabled channel re-add rollback: 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: rollbackChannelAdd() clears current tokens, re-saves snapshot.priorCreds only when getCredential() found values, attempts onboardProviders.upsertMessagingProviders(), and always reports gateway-providers residual.
  • Complete the source-of-truth plan for best-effort rollback (src/lib/actions/sandbox/policy-channel.ts:369): The PR introduces localized recovery behavior for a mixed gateway/registry/policy state, but the source-of-truth review is not fully answered. The invalid state is clear, but the code still creates a transient mixed state for token-backed channels by persisting credentials, upserting gateway providers, and writing the registry before the fallible policy apply step.
    • Recommendation: Prefer making the mixed state impossible by moving all fallible policy work before gateway/registry/provider mutation where feasible. If best-effort rollback remains, document why the source cannot be fixed in this PR, what regression proves the real boundary cannot regress, and when the rollback workaround can be removed.
    • Evidence: applyChannelRemoveToGatewayAndRegistry() accepts { bestEffort: true }; rollbackChannelAdd() calls it after applyPreset failure; token-backed add still calls persistChannelTokens() and applyChannelAddToGatewayAndRegistry() before applyChannelPresetIfAvailable().
  • Keep re-add rollback tied to the gateway credential source of truth (src/lib/actions/sandbox/policy-channel.ts:918): Already-enabled channel rollback restores registry/hash state and optionally re-saves env-staged credentials, but it cannot prove that the OpenShell gateway provider credential has returned to its prior value. If the environment already contains the new rotation token, or lacks the old token, rollback can diverge from the gateway credential source of record.
    • Recommendation: Prefer a gateway/source-of-truth snapshot and restore transaction, or reorder the flow so provider overwrite cannot happen before all fallible policy work succeeds. If best-effort rollback remains, add a negative test where an already-enabled channel has prior registry/hash state but no prior env value or a different new env token, and keep operator guidance explicit that gateway verification is required.
    • Evidence: rollbackChannelAdd() snapshots priorCreds from getCredential(), restores registry providerCredentialHashes, clears current tokens, re-saves snapshot.priorCreds only when env provided values, attempts provider re-upsert, and always reports gateway-providers residual. src/lib/credentials/store.ts and docs/security/credential-storage.mdx state that credentials are env-only on the host and the OpenShell gateway is the system of record.
  • Add targeted runtime validation for the policy/gateway/registry boundary (test/channels-add-preset.test.ts:584): The unit coverage is much stronger and covers the linked WhatsApp missing-preset repro plus rollback branches, but most behavior tests still monkeypatch policies, registry, gateway recovery, provider upsert, and OpenShell execution. The changed behavior spans real preset files under the installed source tree, policy parsing/application, OpenShell gateway provider operations, registry writes, CLI exit behavior, and rebuild prompting.
    • Recommendation: Add or identify a targeted runtime/integration validation that hides whatsapp.yaml in a controlled install/source tree and verifies non-zero exit, no registry write, no provider work, no policy preset application, and no rebuild prompt. Where feasible, also cover a post-write applyPreset failure through the real provider/registry boundary.
    • Evidence: buildPreamble() stubs policies.loadPreset/applyPreset, registry, recoverNamedGatewayRuntime, upsertMessagingProviders, and runOpenshell. The deterministic test-depth context recommends runtime validation for the changed runtime/sandbox/infrastructure paths.
  • Align rollback wording with env-only credential storage (docs/manage-sandboxes/messaging-channels.mdx:171): The docs now correctly warn that already-enabled re-add rollback flags gateway-providers residual, but they also say NemoClaw restores “on-disk credentials.” That conflicts with the credential storage source of truth: NemoClaw does not persist provider credentials to host disk, and the OpenShell gateway is the only system of record.
    • Recommendation: Replace “on-disk credentials” with wording that reflects what the code can actually restore, such as staged environment credentials when available, registry credential hashes, and a best-effort gateway provider re-upsert. Apply the same correction in docs/reference/commands.mdx.
    • Evidence: docs/manage-sandboxes/messaging-channels.mdx:171 and docs/reference/commands.mdx:730 use “on-disk credentials”; src/lib/credentials/store.ts says host credentials are held only in process.env and nothing is written to disk; docs/security/credential-storage.mdx says the OpenShell gateway is the only system of record.

🌱 Nice ideas

  • None.
Since last review details

Current findings:

  • Source-of-truth review needed: Best-effort channel-add rollback after post-write policy apply failure: 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: applyChannelRemoveToGatewayAndRegistry() accepts { bestEffort: true }; rollbackChannelAdd() calls it for fresh-add apply failure; token-backed add still mutates credentials/gateway/registry before applying the preset.
  • Source-of-truth review needed: Already-enabled channel re-add rollback: 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: rollbackChannelAdd() clears current tokens, re-saves snapshot.priorCreds only when getCredential() found values, attempts onboardProviders.upsertMessagingProviders(), and always reports gateway-providers residual.
  • Offset the policy-channel.ts monolith growth (src/lib/actions/sandbox/policy-channel.ts:365): This PR adds preset preflight, best-effort rollback, residual-state handling, and re-add recovery to an already-large sandbox action file. The deterministic drift check reports policy-channel.ts grew from 1230 to 1345 lines (+115), increasing maintenance risk in a high-risk gateway/policy/credential boundary.
    • Recommendation: Extract the new channel-add preflight and rollback behavior into a focused helper module, or offset the growth with nearby cleanup before merge.
    • Evidence: The diff adds bestEffort support to applyChannelRemoveToGatewayAndRegistry(), adds preset preflight in addSandboxChannel(), and adds rollbackChannelAdd(), while the file remains over 1300 lines.
  • Complete the source-of-truth plan for best-effort rollback (src/lib/actions/sandbox/policy-channel.ts:369): The PR introduces localized recovery behavior for a mixed gateway/registry/policy state, but the source-of-truth review is not fully answered. The invalid state is clear, but the code still creates a transient mixed state for token-backed channels by persisting credentials, upserting gateway providers, and writing the registry before the fallible policy apply step.
    • Recommendation: Prefer making the mixed state impossible by moving all fallible policy work before gateway/registry/provider mutation where feasible. If best-effort rollback remains, document why the source cannot be fixed in this PR, what regression proves the real boundary cannot regress, and when the rollback workaround can be removed.
    • Evidence: applyChannelRemoveToGatewayAndRegistry() accepts { bestEffort: true }; rollbackChannelAdd() calls it after applyPreset failure; token-backed add still calls persistChannelTokens() and applyChannelAddToGatewayAndRegistry() before applyChannelPresetIfAvailable().
  • Keep re-add rollback tied to the gateway credential source of truth (src/lib/actions/sandbox/policy-channel.ts:918): Already-enabled channel rollback restores registry/hash state and optionally re-saves env-staged credentials, but it cannot prove that the OpenShell gateway provider credential has returned to its prior value. If the environment already contains the new rotation token, or lacks the old token, rollback can diverge from the gateway credential source of record.
    • Recommendation: Prefer a gateway/source-of-truth snapshot and restore transaction, or reorder the flow so provider overwrite cannot happen before all fallible policy work succeeds. If best-effort rollback remains, add a negative test where an already-enabled channel has prior registry/hash state but no prior env value or a different new env token, and keep operator guidance explicit that gateway verification is required.
    • Evidence: rollbackChannelAdd() snapshots priorCreds from getCredential(), restores registry providerCredentialHashes, clears current tokens, re-saves snapshot.priorCreds only when env provided values, attempts provider re-upsert, and always reports gateway-providers residual. src/lib/credentials/store.ts and docs/security/credential-storage.mdx state that credentials are env-only on the host and the OpenShell gateway is the system of record.
  • Add targeted runtime validation for the policy/gateway/registry boundary (test/channels-add-preset.test.ts:584): The unit coverage is much stronger and covers the linked WhatsApp missing-preset repro plus rollback branches, but most behavior tests still monkeypatch policies, registry, gateway recovery, provider upsert, and OpenShell execution. The changed behavior spans real preset files under the installed source tree, policy parsing/application, OpenShell gateway provider operations, registry writes, CLI exit behavior, and rebuild prompting.
    • Recommendation: Add or identify a targeted runtime/integration validation that hides whatsapp.yaml in a controlled install/source tree and verifies non-zero exit, no registry write, no provider work, no policy preset application, and no rebuild prompt. Where feasible, also cover a post-write applyPreset failure through the real provider/registry boundary.
    • Evidence: buildPreamble() stubs policies.loadPreset/applyPreset, registry, recoverNamedGatewayRuntime, upsertMessagingProviders, and runOpenshell. The deterministic test-depth context recommends runtime validation for the changed runtime/sandbox/infrastructure paths.
  • Align rollback wording with env-only credential storage (docs/manage-sandboxes/messaging-channels.mdx:171): The docs now correctly warn that already-enabled re-add rollback flags gateway-providers residual, but they also say NemoClaw restores “on-disk credentials.” That conflicts with the credential storage source of truth: NemoClaw does not persist provider credentials to host disk, and the OpenShell gateway is the only system of record.
    • Recommendation: Replace “on-disk credentials” with wording that reflects what the code can actually restore, such as staged environment credentials when available, registry credential hashes, and a best-effort gateway provider re-upsert. Apply the same correction in docs/reference/commands.mdx.
    • Evidence: docs/manage-sandboxes/messaging-channels.mdx:171 and docs/reference/commands.mdx:730 use “on-disk credentials”; src/lib/credentials/store.ts says host credentials are held only in process.env and nothing is written to disk; docs/security/credential-storage.mdx says the OpenShell gateway is the only system of record.

Workflow run details

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

@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26711436094
Target ref: 63507a34e88a1a390dbb4c36b569abdc9c58f6b1
Workflow ref: main
Requested jobs: channels-add-remove-e2e
Summary: 1 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
@github-actions
Copy link
Copy Markdown
Contributor

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@docs/manage-sandboxes/messaging-channels.mdx`:
- Around line 167-168: The two-sentence paragraph describing `channels add`
should be split so each sentence is on its own line and the em dash before the
remediation instruction should be replaced with a period; edit the block that
starts with "`channels add` requires the matching built-in network policy preset
YAML..." so the first sentence ends after "sandbox is never left advertising a
channel without a matching network policy." and the second sentence begins with
"If the file is present..." and ends after "rebuild prompt.", then convert the
em dash in the remediation sentence after "apply itself fails" into a period and
put "restore the preset YAML and re-run `nemoclaw <sandbox> channels add
<channel>`." on its own line.

In `@docs/reference/commands.mdx`:
- Line 726: The sentence in the docs line about NemoClaw packs multiple
sentences onto one line and uses an em dash; split that paragraph into separate
lines with one sentence per line and replace the em dash with a period, e.g.
break the long line starting with "NemoClaw requires..." into three separate
sentences/lines describing (1) missing preset YAML behavior, (2) behavior when
the file is present and apply occurs, and (3) recovery instruction starting with
"restore the preset YAML and re-run `nemoclaw <name> channels add <channel>`".
🪄 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: 0fd7308a-cb1a-4806-aa4d-dd5969adb849

📥 Commits

Reviewing files that changed from the base of the PR and between 63507a3 and 1f9359a.

📒 Files selected for processing (4)
  • docs/manage-sandboxes/messaging-channels.mdx
  • docs/reference/commands.mdx
  • src/lib/actions/sandbox/policy-channel.ts
  • test/channels-add-preset.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/actions/sandbox/policy-channel.ts

Comment thread docs/manage-sandboxes/messaging-channels.mdx Outdated
Comment thread docs/reference/commands.mdx Outdated
@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26711992585
Target ref: 1f9359a2c7d958231f4d2c6d1981d1f4fa190e48
Workflow ref: main
Requested jobs: channels-add-remove-e2e,messaging-providers-e2e
Summary: 2 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success
messaging-providers-e2e ✅ success

… style

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/manage-sandboxes/messaging-channels.mdx (1)

168-170: 💤 Low value

Consider varying sentence structure to improve readability.

Three consecutive sentences begin with "If", creating a repetitive pattern. While grammatically correct, varying the structure would improve flow.

💡 Possible rewrite
-If the file is missing, the command exits with a non-zero status before any token prompt, registry write, or rebuild prompt, so the sandbox is never left advertising a channel without a matching network policy.
-If the file is present, `channels add` applies the preset to the sandbox automatically before the rebuild so the bridge has egress to its upstream API.
-If the apply itself fails, the command exits with a non-zero status without prompting for rebuild.
+When the file is missing, the command exits with a non-zero status before any token prompt, registry write, or rebuild prompt, so the sandbox is never left advertising a channel without a matching network policy.
+When the file is present, `channels add` applies the preset to the sandbox automatically before the rebuild so the bridge has egress to its upstream API.
+Should the apply itself fail, the command exits with a non-zero status without prompting for rebuild.
🤖 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 `@docs/manage-sandboxes/messaging-channels.mdx` around lines 168 - 170, Reword
the three consecutive sentences starting with "If" to vary sentence openings and
improve flow: keep the same facts about the missing file (command exits non-zero
before prompts so sandbox isn't left advertising a channel), the present file
behavior (`channels add` auto-applies the preset before rebuild so bridge has
egress), and the failed-apply behavior (command exits non-zero without prompting
for rebuild), but change sentence structure — e.g., start one sentence with the
consequence, another with the condition using a different phrasing, and the
third as a dependent clause — updating the lines that contain "If the file is
missing", "`channels add` applies", and "If the apply itself fails".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/manage-sandboxes/messaging-channels.mdx`:
- Line 168: Rewrite the passive sentence in the given paragraph to active voice:
replace "so the sandbox is never left advertising a channel without a matching
network policy" with an active construction such as "so the command prevents the
sandbox from advertising a channel without a matching network policy." Update
the sentence that begins "If the file is missing, the command exits..." in the
messaging-channels.mdx content to use this active phrasing while preserving
meaning.

---

Nitpick comments:
In `@docs/manage-sandboxes/messaging-channels.mdx`:
- Around line 168-170: Reword the three consecutive sentences starting with "If"
to vary sentence openings and improve flow: keep the same facts about the
missing file (command exits non-zero before prompts so sandbox isn't left
advertising a channel), the present file behavior (`channels add` auto-applies
the preset before rebuild so bridge has egress), and the failed-apply behavior
(command exits non-zero without prompting for rebuild), but change sentence
structure — e.g., start one sentence with the consequence, another with the
condition using a different phrasing, and the third as a dependent clause —
updating the lines that contain "If the file is missing", "`channels add`
applies", and "If the apply itself fails".
🪄 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: 070d214f-3545-41cc-80ef-5431b1b49e8a

📥 Commits

Reviewing files that changed from the base of the PR and between 1f9359a and 2f7f685.

📒 Files selected for processing (4)
  • docs/manage-sandboxes/messaging-channels.mdx
  • docs/reference/commands.mdx
  • src/lib/actions/sandbox/policy-channel.ts
  • test/channels-add-preset.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/actions/sandbox/policy-channel.ts
  • docs/reference/commands.mdx

Comment thread docs/manage-sandboxes/messaging-channels.mdx Outdated
…ay rollback

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26712645489
Target ref: 2f7f685579b215710cacec721745ccd06c5d1bbd
Workflow ref: main
Requested jobs: channels-add-remove-e2e,messaging-providers-e2e
Summary: 2 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success
messaging-providers-e2e ✅ success

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
docs/manage-sandboxes/messaging-channels.mdx (1)

170-170: ⚡ Quick win

Add article before "rebuild" for consistency.

The phrase "without prompting for rebuild" treats "rebuild" as an uncountable noun, but elsewhere in this document "rebuild" consistently takes an article as a countable noun: "the rebuild" (lines 169, 172, 177, 236, 238), "a manual rebuild" (line 184).

📝 Suggested fix
-When the apply step itself fails after the registry write, NemoClaw rolls back the bridge providers, the `messagingChannels` entry, and the persisted credentials, then exits without prompting for rebuild.
+When the apply step itself fails after the registry write, NemoClaw rolls back the bridge providers, the `messagingChannels` entry, and the persisted credentials, then exits without prompting for a rebuild.
🤖 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 `@docs/manage-sandboxes/messaging-channels.mdx` at line 170, The sentence
containing "without prompting for rebuild" should include the definite article
to match the document's consistent usage; update that phrase to "without
prompting for the rebuild" in the same sentence that starts "When the apply step
itself fails after the registry write, NemoClaw rolls back the bridge providers,
the `messagingChannels` entry, and the persisted credentials, then exits without
prompting for rebuild" so it reads "...then exits without prompting for the
rebuild."
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@docs/manage-sandboxes/messaging-channels.mdx`:
- Line 170: The sentence containing "without prompting for rebuild" should
include the definite article to match the document's consistent usage; update
that phrase to "without prompting for the rebuild" in the same sentence that
starts "When the apply step itself fails after the registry write, NemoClaw
rolls back the bridge providers, the `messagingChannels` entry, and the
persisted credentials, then exits without prompting for rebuild" so it reads
"...then exits without prompting for the rebuild."

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d82988eb-fc01-4d45-af25-0438299b37ab

📥 Commits

Reviewing files that changed from the base of the PR and between 2f7f685 and 0c0a4a9.

📒 Files selected for processing (4)
  • docs/manage-sandboxes/messaging-channels.mdx
  • docs/reference/commands.mdx
  • src/lib/actions/sandbox/policy-channel.ts
  • test/channels-add-preset.test.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/reference/commands.mdx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/actions/sandbox/policy-channel.ts
  • test/channels-add-preset.test.ts

@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26713016536
Target ref: 0c0a4a93cf875f8822c150d50faa9f9aa4494ae6
Workflow ref: main
Requested jobs: channels-add-remove-e2e,messaging-providers-e2e
Summary: 2 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success
messaging-providers-e2e ✅ success

@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26713559497
Target ref: 3416e2a750e9849b20362b5e5db4cd43d38994d3
Workflow ref: main
Requested jobs: channels-add-remove-e2e,messaging-providers-e2e
Summary: 2 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success
messaging-providers-e2e ✅ success

…d re-add

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/lib/actions/sandbox/policy-channel.ts (1)

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

Make --dry-run honor the new preset preflight.

Right now --dry-run returns before loadPreset / parsePresetPolicyKeys run, so it exits 0 even when the real channels add would now fail on a missing or malformed built-in preset. That makes the dry-run contract lie about whether the command is actually runnable.

Suggested change
-  if (dryRun) {
-    console.log(`  --dry-run: would enable channel '${canonical}' for '${sandboxName}'.`);
-    return;
-  }
-
   const presetContent = policies.loadPreset(canonical);
   const presetPolicyKeys =
     presetContent === null ? [] : policies.parsePresetPolicyKeys(presetContent);
   if (presetContent === null || presetPolicyKeys.length === 0) {
     if (presetContent !== null && presetPolicyKeys.length === 0) {
       console.error(
         `  Preset YAML for channel '${canonical}' has no parseable entries under 'network_policies:'.`,
       );
     }
     console.error(
       `    Restore the preset YAML and re-run: ${CLI_NAME} ${sandboxName} channels add ${canonical}`,
     );
     process.exit(1);
   }
+
+  if (dryRun) {
+    console.log(`  --dry-run: would enable channel '${canonical}' for '${sandboxName}'.`);
+    return;
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/actions/sandbox/policy-channel.ts` around lines 810 - 828, The
dry-run branch returns early and skips the new preset preflight, so dryRun in
the channel add flow can report success even when policies.loadPreset(canonical)
or policies.parsePresetPolicyKeys(...) would fail; modify the control flow in
the function handling the --dry-run (check the dryRun variable) so that it still
calls policies.loadPreset(canonical) and
policies.parsePresetPolicyKeys(presetContent) and performs the same
validation/error handling (including the console.error messages and
process.exit(1) path using sandboxName, canonical, and CLI_NAME) but only skips
the actual side-effect of enabling the channel—i.e., run the preset preflight
before returning for dryRun.
🧹 Nitpick comments (1)
test/channels-add-preset.test.ts (1)

1374-1388: ⚡ Quick win

Validate preset contents, not just file presence.

This guard still passes if <channel>.yaml exists but is malformed or has no parseable network_policies, which are the exact failure modes addSandboxChannel() now treats as fatal. Parsing each on-disk preset here would make the source-of-truth test actually cover the new contract.

♻️ Tighten the source-of-truth check
   it("every channel registered in KNOWN_CHANNELS ships a matching preset YAML on disk", () => {
     const { knownChannelNames } = require(path.join(repoRoot, "dist", "lib", "sandbox", "channels.js")) as {
       knownChannelNames: () => string[];
     };
+    const { parsePresetPolicyKeys } = require(path.join(repoRoot, "dist", "lib", "policy", "index.js")) as {
+      parsePresetPolicyKeys: (content: string) => string[];
+    };
     const presetDir = path.join(repoRoot, "nemoclaw-blueprint", "policies", "presets");
     const missing: string[] = [];
     for (const name of knownChannelNames()) {
       const file = path.join(presetDir, `${name}.yaml`);
-      if (!fs.existsSync(file)) missing.push(file);
+      if (!fs.existsSync(file)) {
+        missing.push(file);
+        continue;
+      }
+      const content = fs.readFileSync(file, "utf8");
+      if (parsePresetPolicyKeys(content).length === 0) {
+        missing.push(`${file} (no parseable network_policies)`);
+      }
     }
     assert.deepEqual(
       missing,
       [],
       `every channel in KNOWN_CHANNELS must have a matching preset YAML; missing: ${missing.join(", ")}`,
🤖 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/channels-add-preset.test.ts` around lines 1374 - 1388, The test
currently only checks that a preset file exists for each channel; instead, load
and parse each YAML preset from presetDir for every name from
knownChannelNames(), and assert that parsing succeeds and the resulting object
contains a non-empty network_policies (or the exact key/shape
addSandboxChannel() expects). Update the loop that builds missing to also read
fs.readFileSync(file, "utf8"), parse with the same YAML loader used in
production (or require the preset parser used by addSandboxChannel()), and push
file onto missing (or a new failures list) if parsing throws or network_policies
is absent/empty; finally assert failures is empty with a helpful message
referencing addSandboxChannel()'s contract.
🤖 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/actions/sandbox/policy-channel.ts`:
- Around line 924-945: The rollback currently calls
onboardProviders.upsertMessagingProviders which can call process.exit on failure
and therefore prevents the registry restore; change this to a non-exiting,
best-effort provider-restore path (e.g. call a non-exiting variant like
onboardProviders.upsertMessagingProvidersBestEffort(...) or pass a { bestEffort:
true } flag to upsertMessagingProviders) inside a try/catch/finally so that any
gateway restore errors are caught and result in
residual.push("gateway-providers"), and ensure registry.updateSandbox(...) is
always executed (move it to finally or after the catch) so the prior registry
state is restored even when the gateway restore flakes.

---

Outside diff comments:
In `@src/lib/actions/sandbox/policy-channel.ts`:
- Around line 810-828: The dry-run branch returns early and skips the new preset
preflight, so dryRun in the channel add flow can report success even when
policies.loadPreset(canonical) or policies.parsePresetPolicyKeys(...) would
fail; modify the control flow in the function handling the --dry-run (check the
dryRun variable) so that it still calls policies.loadPreset(canonical) and
policies.parsePresetPolicyKeys(presetContent) and performs the same
validation/error handling (including the console.error messages and
process.exit(1) path using sandboxName, canonical, and CLI_NAME) but only skips
the actual side-effect of enabling the channel—i.e., run the preset preflight
before returning for dryRun.

---

Nitpick comments:
In `@test/channels-add-preset.test.ts`:
- Around line 1374-1388: The test currently only checks that a preset file
exists for each channel; instead, load and parse each YAML preset from presetDir
for every name from knownChannelNames(), and assert that parsing succeeds and
the resulting object contains a non-empty network_policies (or the exact
key/shape addSandboxChannel() expects). Update the loop that builds missing to
also read fs.readFileSync(file, "utf8"), parse with the same YAML loader used in
production (or require the preset parser used by addSandboxChannel()), and push
file onto missing (or a new failures list) if parsing throws or network_policies
is absent/empty; finally assert failures is empty with a helpful message
referencing addSandboxChannel()'s contract.
🪄 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: 8e731a0f-5c07-40f2-adb2-85f42e707d2a

📥 Commits

Reviewing files that changed from the base of the PR and between 3416e2a and d7b6402.

📒 Files selected for processing (5)
  • docs/manage-sandboxes/messaging-channels.mdx
  • docs/reference/commands.mdx
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/policy/index.ts
  • test/channels-add-preset.test.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/manage-sandboxes/messaging-channels.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/reference/commands.mdx

Comment thread src/lib/actions/sandbox/policy-channel.ts Outdated
@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26714552896
Target ref: d7b64028e6b30ea7684fb7240b540a04995920c1
Workflow ref: main
Requested jobs: channels-add-remove-e2e,messaging-providers-e2e
Summary: 2 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success
messaging-providers-e2e ✅ success

…ilure safety

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26715309625
Target ref: c12353992f00cd968c95972a9c149a6065ad2ba1
Workflow ref: main
Requested jobs: channels-add-remove-e2e,messaging-providers-e2e
Summary: 2 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success
messaging-providers-e2e ✅ success

@laitingsheng laitingsheng added the v0.0.56 Release target label May 31, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26715901484
Target ref: 3b3c520b07653471121e4a19838f32ea5ea62cfe
Workflow ref: main
Requested jobs: channels-add-remove-e2e,messaging-providers-e2e
Summary: 2 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success
messaging-providers-e2e ✅ success

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix v0.0.56 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[All Platforms][Agent&Skills] 'channels add whatsapp' updates messagingChannels and succeeds even when whatsapp preset file is missing

1 participant