Skip to content

refactor(messaging): migrate conflict detection to manifest-plan architecture (phase 4a, #4392)#4908

Open
sandl99 wants to merge 31 commits into
mainfrom
feat/phase-4a-messaging-conflict-plan-driven
Open

refactor(messaging): migrate conflict detection to manifest-plan architecture (phase 4a, #4392)#4908
sandl99 wants to merge 31 commits into
mainfrom
feat/phase-4a-messaging-conflict-plan-driven

Conversation

@sandl99
Copy link
Copy Markdown
Contributor

@sandl99 sandl99 commented Jun 7, 2026

Summary

Migrates cross-sandbox messaging credential conflict detection to the manifest-plan architecture (phase 4a of #3896). Core detection logic now lives in src/lib/messaging/applier/conflict-detection.ts; the legacy src/lib/messaging-conflict.ts adapter has been removed; and current callers import the conflict helpers from src/lib/messaging/applier.

onboard.ts now reads conflict requests directly from the compiled SandboxMessagingPlan, so conflict detection is plan-driven rather than built from legacy channel constants.

Related Issue

Closes #4392. Part of #3896.

Changes

  • src/lib/messaging/applier/conflict-detection.ts contains the conflict detection surface: tri-state gateway probe factory, plan-to-request helpers, active-channel resolution, registry-backed conflict/overlap helpers, and legacy channel-presence backfill.
  • src/lib/messaging/applier/index.ts re-exports the conflict-detection helpers for callers.
  • src/lib/messaging-conflict.ts was deleted; onboard.ts, status-command-deps.ts, and policy-channel.ts now import from messaging/applier.
  • Legacy channel-presence tests moved to src/lib/messaging/applier/conflict-detection-legacy.test.ts; plan and entry behavior remain covered by the applier tests.
  • Token rotation validation now checks registry plan credential hashes instead of the removed legacy hash field.

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

  • npm run typecheck:cli
  • npx vitest run --project cli src/lib/messaging/applier/conflict-detection-entry.test.ts src/lib/messaging/applier/conflict-detection-plan.test.ts src/lib/messaging/applier/conflict-detection-legacy.test.ts src/lib/actions/sandbox/policy-channel-conflict.test.ts src/lib/status-command-deps.test.ts
  • bash -n test/e2e/test-token-rotation.sh
  • git diff --check
  • No secrets, API keys, or credentials committed
  • npm test / full CLI suite: unrelated test/cli/list-inference.test.ts timeout reproduced under suite load

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

Summary by CodeRabbit

  • Refactor
    • Restructured messaging channel conflict detection to use compiled messaging plans instead of legacy credential hash tracking for improved accuracy and streamlined state management.

sandl99 and others added 6 commits June 7, 2026 11:49
Stores the compiled SandboxMessagingPlan in the onboard session so that
resume runs can restore the plan to env without re-running enrollment
hooks (token paste, QR pairing). Fixes the gap where the registry entry
lost its `messaging` field on rebuild because the plan was only held in
a process env var that didn't survive across process restarts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…el-setup

Exports readMessagingPlanFromEnv and writePlanToEnv from
messaging-channel-setup.ts (which already owns MessagingSetupApplier)
to keep src/lib/onboard.ts from growing. Collapses the one-name
messaging-channel-setup require into a single line to free headroom.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…an persistence

- Extract parseSandboxMessagingPlan to messaging-plan-session.ts to
  keep onboard-session.ts growth under the monolith threshold
- Guard plan restoration with sandbox-name + agent identity check so
  stale plans from renamed sandboxes or agent switches are not reused
- Add three behavior assertions in sandbox.test.ts: fresh setup
  persists env plan to session; matching plan is restored to env on
  non-interactive resume; mismatched sandbox name skips restoration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tive resume

rebuild.ts stages an authoritative plan from the registry (which reflects
post-stop/-start channel mutations) before calling onboard --resume.
Previously, the session plan restoration was unconditionally overwriting
that staged plan, causing stopped channels to reappear as active after
rebuild.

Now the handler checks the env first: if a plan is already staged
(rebuild path), it is used as-is. The session plan is only restored when
the env is empty, covering the plain process-restart resume case this PR
was originally targeting.

Also adds a test asserting the rebuild-path preference.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- On non-interactive resume, restore plan from registry (always current
  after stop/start/add/remove) instead of stale session snapshot;
  env-first priority preserved so rebuild.ts staging still wins

- In rebuild.ts, persist the staged plan to the session alongside
  messagingChannels/disabledChannels/messagingChannelConfig so the
  session is fully consistent during the rebuild window

- Add getChannelsFromPlan, getDisabledChannelsFromPlan, and
  getMessagingChannelConfigFromPlan helpers in messaging-plan-session.ts
  so the next PR can replace the three individual session fields with
  plan-derived reads

- Move MessagingHostStateApplier re-export to messaging-channel-setup
  and getRegistrySandboxMessagingPlan helper to keep onboard.ts net-neutral

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…itecture (phase 4a)

- Add src/lib/messaging/applier/conflict-detection.ts with all core logic:
  ConflictRegistryEntry minimal interface, createMessagingConflictProbe factory
  (consolidates the duplicated tri-state probe pattern from onboard.ts,
  policy-channel.ts, and status-command-deps.ts), plan-to-request helpers
  (getActiveChannelIdsFromPlan, getCredentialHashesFromPlan,
  planToConflictChannelRequests), plan-preferred/legacy-fallback entry
  resolution (resolveActiveChannelsFromEntry, resolveCredentialHashesFromEntry),
  and pure detection functions (findConflictsInEntries, detectAllOverlapsInEntries,
  backfillLegacyEntryChannels)

- Rewrite messaging-conflict.ts as a thin public adapter: no detection logic
  inside, all three public exports delegate to applier functions, re-exports
  createMessagingConflictProbe so callers don't need to import from applier
  directly; removes getChannelDef/getChannelTokenKeys import (stored hashes
  are self-describing — no channel-constant lookup needed)

- Update onboard.ts conflict-check block: remove makeConflictProbe() and the
  MESSAGING_CHANNELS/hashCredential block; use createMessagingConflictProbe
  with injected openshell deps and findChannelConflictsFromPlan from plan

- Add plan-path tests: planToConflictChannelRequests grouping and exclusions,
  findChannelConflictsFromPlan matching/disabled/no-hash cases, plan-only
  registry entries in findChannelConflicts and findAllOverlaps

Closes #4392

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Jun 7, 2026

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

coderabbitai Bot commented Jun 7, 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: c94063fc-8485-46e3-8df1-5c2cc12b6888

📥 Commits

Reviewing files that changed from the base of the PR and between bd847fc and f5839b2.

📒 Files selected for processing (9)
  • src/lib/messaging/applier/conflict-detection-legacy.test.ts
  • src/lib/messaging/applier/conflict-detection/backfill.ts
  • src/lib/messaging/applier/conflict-detection/entries.ts
  • src/lib/messaging/applier/conflict-detection/index.ts
  • src/lib/messaging/applier/conflict-detection/manifest-metadata.ts
  • src/lib/messaging/applier/conflict-detection/plan.ts
  • src/lib/messaging/applier/conflict-detection/probe.ts
  • src/lib/messaging/applier/conflict-detection/registry.ts
  • src/lib/messaging/applier/conflict-detection/types.ts
✅ Files skipped from review due to trivial changes (1)
  • src/lib/messaging/applier/conflict-detection/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/messaging/applier/conflict-detection-legacy.test.ts

📝 Walkthrough

Walkthrough

This PR refactors messaging conflict detection from legacy hardcoded channel metadata to manifest/plan-driven credential hashing. It removes provider-hash field persistence, introduces new conflict-detection modules with request/entry/pair reasoning, rewires runtime conflict gates and channel management to use compiled plan data, and migrates all unit and integration tests to plan-backed fixtures and assertions.

Changes

Messaging Conflict Detection Migration

Layer / File(s) Summary
Conflict detection types and public contracts
src/lib/messaging/applier/conflict-detection/types.ts, src/lib/messaging/applier/conflict-detection/index.ts, src/lib/messaging/applier/index.ts
Defines tri-state probe results, conflict reasons, request/response shapes, and registry abstractions; exposes through barrel exports and applier index.
Manifest metadata extraction and plan utilities
src/lib/messaging/applier/conflict-detection/manifest-metadata.ts, src/lib/messaging/applier/conflict-detection/plan.ts
Derives credential env keys and provider suffixes from built-in manifests; provides functions to compute active channels, collect hashes, and convert plans to conflict requests.
Core conflict reasoning and entry resolution
src/lib/messaging/applier/conflict-detection/entries.ts
Resolves active channels and credential hashes from registry entries; compares request vs. entry hashes; detects conflicts between entry pairs and scans for all overlaps per channel.
Registry-backed conflict detection and probe factory
src/lib/messaging/applier/conflict-detection/registry.ts, src/lib/messaging/applier/conflict-detection/probe.ts
Wraps core conflict logic with registry lookups and request normalization; creates memoized gateway-liveness-aware probes that short-circuit on gateway failure.
Legacy channel presence backfill
src/lib/messaging/applier/conflict-detection/backfill.ts
Probes for manifest provider presence to infer messagingChannels for pre-plan registry entries; skips updates on probe errors to avoid persisting transient failures.
Plan credential hash generation at compile time
src/lib/messaging/compiler/engines/credential-binding-engine.ts
Computes SHA-256 hashes from environment variables only when credentials are available; conditionally includes credentialHash in plan bindings.
Registry schema and data model updates
src/lib/inventory/index.ts, src/lib/state/registry.ts, src/lib/messaging/compiler/workflow-planner.ts, src/lib/onboard/messaging-credentials.ts
Removes providerCredentialHashes from persisted SandboxEntry schema; updates credential-availability derivation and rotation detection to use plan.credentialBindings instead of legacy hashes; adds agent identification fields.
Runtime conflict flow and channel add/remove/rebuild wiring
src/lib/onboard.ts, src/lib/actions/sandbox/policy-channel.ts, src/lib/actions/sandbox/rebuild.ts, src/lib/status-command-deps.ts
Reworks onboard/channels-add conflict checks to use plan-driven hashes and probe/backfill APIs; removes provider hash persistence and restoration; adds explicit error handling; updates import sources to new conflict-detection modules.
Conflict test fixtures and helper builders
test/helpers/messaging-conflict-fixtures.ts
Provides factories for building SandboxMessagingPlan objects, channel/binding fixtures, and plan-entry wrappers for use in conflict detection tests.
Conflict detection module test suites
src/lib/messaging/applier/conflict-detection-entry.test.ts, src/lib/messaging/applier/conflict-detection-plan.test.ts, src/lib/messaging/applier/conflict-detection-multi-credential.test.ts, src/lib/messaging/applier/conflict-detection-overlap.test.ts, src/lib/messaging/applier/conflict-detection-legacy.test.ts
Comprehensive test coverage for entry resolution, request/entry/pair conflict reasoning, plan helpers, legacy registry backfill, Slack multi-credential cases, and overlap detection.
Runtime and integration test migrations
test/channels-add-preset.test.ts, test/channels-remove-full-teardown.test.ts, test/cli/status-health.test.ts, test/credential-rotation.test.ts, test/e2e/test-token-rotation.sh, test/onboard-messaging.test.ts, test/rebuild-credential-preflight.test.ts, src/lib/messaging/compiler/workflow-planner.test.ts, src/lib/actions/sandbox/policy-channel-conflict.test.ts, ci/test-file-size-budget.json
Removes providerCredentialHashes expectations from mocks and assertions; adopts plan-backed fixtures; verifies conflict error paths including non-interactive abort and --force override; updates e2e credential hash queries to use plan bindings; adjusts test size budgets.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • #4392: Phase 4a objective to migrate messaging credential conflict detection from legacy channel metadata to manifest/plan-driven approach, which this PR fully implements.
  • #4393: Phase 4b continuation on credential rotation and registry persistence using plan-backed credentialBindings.

Possibly related PRs

  • NVIDIA/NemoClaw#4901: Implements plan persistence into session and plan loading via readMessagingPlanFromEnv(); this PR's conflict-check path depends on that same plan-loading behavior.
  • NVIDIA/NemoClaw#4652: Implements cross-sandbox messaging channel conflict detection for channels add; this PR refactors that logic to use the new plan-driven conflict-detection helpers.
  • NVIDIA/NemoClaw#4536: Stores SandboxEntry.messaging.plan persistence; this PR then rewires messaging conflict/probe and credential-availability logic to read from sb.messaging.plan.credentialBindings.

Suggested labels

area: onboarding, area: integrations

Suggested reviewers

  • ericksoa
  • cv

Poem

🐰 The plans are compiled, the hashes now shine,
No more legacy ghosts in the provider's design,
Each token compared by its cryptographic soul,
Backfill probes search for channels, making sandboxes whole,
With conflicts detected and tests verified bright,
The messaging realm is made beautifully tight! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.57% 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 clearly describes the main change: migrating messaging conflict detection to a manifest-plan architecture as part of phase 4a, directly addressing the PR's primary objective.
Linked Issues check ✅ Passed The PR implements all core objectives from #4392: plan-driven conflict detection via manifest metadata, removal of legacy providerCredentialHashes, conservative unknown-token handling for bindings without hashes, legacy channel-presence backfill without hash recovery, and comprehensive test coverage for plan/entry/overlap logic.
Out of Scope Changes check ✅ Passed All changes align with #4392 scope: legacy module removal, plan-driven refactoring, manifest metadata extraction, test updates reflecting new architecture, and removal of providerCredentialHashes persistence across registry/state/tests.

✏️ 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 feat/phase-4a-messaging-conflict-plan-driven

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 7, 2026

E2E Advisor Recommendation

Required E2E: messaging-providers-e2e, channels-add-remove-e2e, token-rotation-e2e
Optional E2E: channels-stop-start-e2e, rebuild-openclaw-e2e, diagnostics-e2e

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

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • messaging-providers-e2e (high; timeout 75 minutes): Required because the PR changes onboarding-time messaging credential binding, provider metadata, plan state, and conflict metadata. This job validates the real provider/placeholder/L7-proxy chain for Telegram, Discord, Slack, plus QR-only WhatsApp behavior in a real sandbox.
  • channels-add-remove-e2e (high; timeout 75 minutes): Required because policy-channel.ts and rebuild.ts changes directly affect channels add/remove, gateway provider registration/removal, registry state, policy preset application, and rebuild-after-channel-change behavior.
  • token-rotation-e2e (medium-high; timeout 45 minutes): Required because the PR changes credential hash storage from legacy registry fields to plan-backed bindings and edits the token rotation E2E script. This job validates that rotated Telegram/Discord/Slack credentials propagate through onboard/rebuild without cross-talk.

Optional E2E

  • channels-stop-start-e2e (very high; timeout 120 minutes): Useful adjacent confidence because conflict detection and status overlap logic must ignore disabled channels, and this job exercises stop/start semantics across messaging channels and agents. Not strictly merge-blocking if required add/remove and provider jobs pass.
  • rebuild-openclaw-e2e (high): Useful because rebuild.ts registry preservation changed, but the required channels-add-remove/token-rotation jobs already cover the messaging-sensitive rebuild paths. Run if additional confidence in generic OpenClaw rebuild lifecycle is desired.
  • diagnostics-e2e (medium): Optional status/diagnostics coverage for user-visible health output after moving conflict and credential metadata out of the legacy inventory shape.

New E2E recommendations

  • cross-sandbox messaging credential conflicts (high): Existing E2E jobs validate provider setup, add/remove, and rotation, but there is no clear existing E2E that creates or simulates two real sandboxes and asserts channels add blocks or warns when the second sandbox reuses the same plan-backed Telegram/Slack/Discord credential, including --force and non-interactive fail-closed paths.
    • Suggested test: Add a cross-sandbox channels credential-conflict E2E that seeds or creates two sandboxes, attempts to add the same token-backed channel to both, verifies the conflict warning/abort, and verifies --force proceeds without leaking raw tokens.
  • status overlap reporting for plan-backed entries (medium): Status/inventory now rely on plan-backed credential hashes rather than the removed providerCredentialHashes field. Unit tests cover overlap detection, but a real CLI E2E for nemoclaw status showing matching-token vs unknown-token messaging overlaps would guard the user-visible migration.
    • Suggested test: Add a status messaging-overlap E2E that prepares plan-backed registry entries with matching and distinct credential hashes, runs nemoclaw status, and asserts warnings are accurate and secrets/hashes are not printed.

Dispatch hint

  • Workflow: nightly-e2e.yaml
  • jobs input: messaging-providers-e2e,channels-add-remove-e2e,token-rotation-e2e

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 7, 2026

E2E Scenario Advisor Recommendation

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

Dispatch required scenario E2E:

  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw
  • 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
  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-token-rotation

Workflow run

Full scenario advisor summary

E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required scenario E2E

  • ubuntu-repo-cloud-openclaw: Baseline Ubuntu repo OpenClaw onboarding should run because core onboarding, registry/inventory/status, rebuild preservation, and credential handling changed; this verifies the non-messaging happy path still reaches a ready sandbox with credentials and smoke checks.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw
  • ubuntu-repo-cloud-openclaw-telegram: Telegram is the primary single-token messaging scenario for the changed channel add/conflict-detection, messaging credential binding, and provider attachment paths.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-telegram
  • ubuntu-repo-cloud-openclaw-slack: Slack exercises the multi-credential messaging path directly affected by the new plan-backed conflict detection and credential binding changes.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-slack
  • ubuntu-repo-cloud-openclaw-token-rotation: Token rotation is directly relevant to the credential rotation, messaging credential, channel registry, and rebuild-preservation changes.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-token-rotation

Optional scenario E2E

  • ubuntu-repo-cloud-openclaw-discord: Adjacent OpenClaw messaging scenario covering another single-token bridge; useful if the PR owner wants broader messaging-channel confidence beyond Telegram and Slack.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw-discord
  • ubuntu-repo-cloud-hermes-slack: Optional cross-agent coverage for the same Slack multi-credential messaging surface on Hermes rather than OpenClaw.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes-slack

Relevant changed files

  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/inventory/index.ts
  • src/lib/messaging-conflict.ts
  • src/lib/messaging/applier/conflict-detection/backfill.ts
  • src/lib/messaging/applier/conflict-detection/entries.ts
  • src/lib/messaging/applier/conflict-detection/index.ts
  • src/lib/messaging/applier/conflict-detection/manifest-metadata.ts
  • src/lib/messaging/applier/conflict-detection/plan.ts
  • src/lib/messaging/applier/conflict-detection/probe.ts
  • src/lib/messaging/applier/conflict-detection/registry.ts
  • src/lib/messaging/applier/conflict-detection/types.ts
  • src/lib/messaging/applier/index.ts
  • src/lib/messaging/compiler/engines/credential-binding-engine.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/onboard.ts
  • src/lib/onboard/messaging-credentials.ts
  • src/lib/state/registry.ts
  • src/lib/status-command-deps.ts

Comment thread src/lib/messaging-conflict.ts Fixed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 7, 2026

PR Review Advisor

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

Review findings

🛠️ Needs attention

  • None.

🔎 Worth checking

  • Source-of-truth review needed: `channels add` conflict-check exception handling: 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: `policy-channel.ts` catches conflict errors, aborts non-interactively unless forced, and prompts interactively; this contradicts the issue's best-effort source-of-truth decision.
  • Source-of-truth text still describes channels-add conflict errors as best-effort (src/lib/actions/sandbox/policy-channel.ts:430): Issue Phase 4a: migrate messaging credential conflict detection to manifest plans #4392 says malformed conflict metadata on `channels add` is best-effort and that fail-closed hardening is outside this phase, but the current implementation now logs the conflict-check failure and aborts non-interactively unless `--force` is used. The code is safer and tests cover it, but the documented source-of-truth decision is now stale or contradicts the implemented behavior.
    • Recommendation: Update the linked issue/PR source-of-truth notes to say `channels add` conflict-check errors now fail closed unless explicitly overridden, or adjust the code if best-effort behavior is still intended.
    • Evidence: `checkChannelAddConflict()` catches `findChannelConflicts` errors, prints `Could not verify messaging channel conflicts`, exits in non-interactive mode unless `--force`, and `policy-channel-conflict.test.ts` adds `non-interactive add aborts when the conflict check throws` plus `--force proceeds when the conflict check throws`.

🌱 Nice ideas

  • None.
Consider writing more tests for
  • **Runtime validation** — Onboard aborts before sandbox creation when the freshly compiled env plan has a matching token hash against another plan-backed sandbox.. Pure conflict-detection and channel-add unit coverage is broad, but the changed behavior crosses env-staged messaging plans, registry persistence, OpenShell provider discovery, status backfill, token rotation, and sandbox lifecycle flows that read-only review cannot execute.
  • **Runtime validation** — Onboard ignores a different-sandbox stale `NEMOCLAW_MESSAGING_PLAN_B64` and does not use it to gate or bypass the current sandbox's conflict detection.. Pure conflict-detection and channel-add unit coverage is broad, but the changed behavior crosses env-staged messaging plans, registry persistence, OpenShell provider discovery, status backfill, token rotation, and sandbox lifecycle flows that read-only review cannot execute.
  • **Runtime validation** — Resume with recorded messaging channels but no env or registry plan follows the explicit no-plan behavior without fabricating legacy conflict requests.. Pure conflict-detection and channel-add unit coverage is broad, but the changed behavior crosses env-staged messaging plans, registry persistence, OpenShell provider discovery, status backfill, token rotation, and sandbox lifecycle flows that read-only review cannot execute.
  • **Runtime validation** — `channels add telegram` persists a plan credential hash, then later status or overlap detection reports `matching-token` without any `providerCredentialHashes` field.. Pure conflict-detection and channel-add unit coverage is broad, but the changed behavior crosses env-staged messaging plans, registry persistence, OpenShell provider discovery, status backfill, token rotation, and sandbox lifecycle flows that read-only review cannot execute.
  • **Runtime validation** — Status backfill detects Slack channel presence when only the `-slack-app` provider suffix exists, and does not persist partial results when one Slack suffix probe returns `error`.. Pure conflict-detection and channel-add unit coverage is broad, but the changed behavior crosses env-staged messaging plans, registry persistence, OpenShell provider discovery, status backfill, token rotation, and sandbox lifecycle flows that read-only review cannot execute.
  • **Acceptance clause:** `channels add` conflict checks: malformed conflict metadata is not repaired from legacy sources in Phase 4a. Conflict detection is best-effort for this mutation path unless an explicit same-token or unknown-token conflict is detected; `--force` remains the user override for detected conflicts. Future hardening can fail closed, but that is outside this phase. Regression coverage lives in `policy-channel-conflict.test.ts`. — add test evidence or identify existing coverage. The code still does not repair from legacy sources and `--force` overrides, but current `policy-channel.ts` now fails closed for conflict-check exceptions in non-interactive mode. This is safer, yet contradicts the issue text that says fail-closed hardening is outside this phase.
  • **`channels add` conflict-check exception handling** — `policy-channel-conflict.test.ts` covers non-interactive abort when the conflict check throws and `--force` proceeding.. `policy-channel.ts` catches conflict errors, aborts non-interactively unless forced, and prompts interactively; this contradicts the issue's best-effort source-of-truth decision.
Since last review details

Current findings:

  • Source-of-truth review needed: `channels add` conflict-check exception handling: 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: `policy-channel.ts` catches conflict errors, aborts non-interactively unless forced, and prompts interactively; this contradicts the issue's best-effort source-of-truth decision.
  • Source-of-truth text still describes channels-add conflict errors as best-effort (src/lib/actions/sandbox/policy-channel.ts:430): Issue Phase 4a: migrate messaging credential conflict detection to manifest plans #4392 says malformed conflict metadata on `channels add` is best-effort and that fail-closed hardening is outside this phase, but the current implementation now logs the conflict-check failure and aborts non-interactively unless `--force` is used. The code is safer and tests cover it, but the documented source-of-truth decision is now stale or contradicts the implemented behavior.
    • Recommendation: Update the linked issue/PR source-of-truth notes to say `channels add` conflict-check errors now fail closed unless explicitly overridden, or adjust the code if best-effort behavior is still intended.
    • Evidence: `checkChannelAddConflict()` catches `findChannelConflicts` errors, prints `Could not verify messaging channel conflicts`, exits in non-interactive mode unless `--force`, and `policy-channel-conflict.test.ts` adds `non-interactive add aborts when the conflict check throws` plus `--force proceeds when the conflict check throws`.

Workflow run details

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

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

♻️ Duplicate comments (1)
src/lib/messaging-conflict.ts (1)

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

Remove unused import createMessagingConflictProbe from the import statement.

The import of createMessagingConflictProbe on line 19 is unused because line 28 performs a direct re-export from the same module. The static analysis correctly flags this redundancy.

🧹 Proposed fix
 import {
   backfillLegacyEntryChannels,
-  createMessagingConflictProbe,
   detectAllOverlapsInEntries,
   findConflictsInEntries,
   planToConflictChannelRequests,
   type ConflictMatch,
   type ConflictReason,
   type MessagingConflictProbe,
 } from "./messaging/applier";
🤖 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-conflict.ts` around lines 17 - 28, The import list in
src/lib/messaging-conflict.ts unnecessarily includes
createMessagingConflictProbe even though that symbol is re-exported later;
remove createMessagingConflictProbe from the named imports (the import that
currently includes backfillLegacyEntryChannels, detectAllOverlapsInEntries,
findConflictsInEntries, planToConflictChannelRequests, type ConflictMatch, type
ConflictReason, type MessagingConflictProbe) and leave the explicit export
export { createMessagingConflictProbe } from "./messaging/applier"; unchanged.

Source: Linters/SAST tools

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

Inline comments:
In `@src/lib/onboard.ts`:
- Around line 2808-2811: The checkGatewayLiveness implementation is using stdout
length to decide liveness (treating empty output as "down"); change
checkGatewayLiveness to determine success from the command exit status or thrown
error from runCaptureOpenshell instead of checking typeof result === "string" &&
result.length > 0. Locate the checkGatewayLiveness function and replace the
stdout-content check with a check of runCaptureOpenshell's success (e.g., handle
non-zero exit by catch/return false or inspect a returned status field) so a
successful exit with empty output still yields true; remove the string/length
condition and rely on the command exit semantics exposed by runCaptureOpenshell.

---

Duplicate comments:
In `@src/lib/messaging-conflict.ts`:
- Around line 17-28: The import list in src/lib/messaging-conflict.ts
unnecessarily includes createMessagingConflictProbe even though that symbol is
re-exported later; remove createMessagingConflictProbe from the named imports
(the import that currently includes backfillLegacyEntryChannels,
detectAllOverlapsInEntries, findConflictsInEntries,
planToConflictChannelRequests, type ConflictMatch, type ConflictReason, type
MessagingConflictProbe) and leave the explicit export export {
createMessagingConflictProbe } from "./messaging/applier"; unchanged.
🪄 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: b1a03bce-d211-43d0-a561-8b38d5167f2b

📥 Commits

Reviewing files that changed from the base of the PR and between 673d441 and 6913199.

📒 Files selected for processing (5)
  • src/lib/messaging-conflict.test.ts
  • src/lib/messaging-conflict.ts
  • src/lib/messaging/applier/conflict-detection.ts
  • src/lib/messaging/applier/index.ts
  • src/lib/onboard.ts

Comment thread src/lib/onboard.ts Outdated
sandl99 and others added 2 commits June 7, 2026 15:46
- Remove redundant createMessagingConflictProbe named import from
  messaging-conflict.ts (symbol is already re-exported on the line below;
  flagged by CodeQL unused-import rule)
- Fix checkGatewayLiveness in onboard.ts to use runOpenshell exit status
  instead of stdout length; a healthy gateway with no sandboxes returns
  empty output with status 0, which the previous check incorrectly treated
  as "down"

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Fix credentialHash gate: gate on credentialAvailable (set by the compiler
  for all real onboarding flows) instead of credentialHash (not yet populated),
  which previously caused the conflict check to be silently skipped for all
  manifest-plan onboarding; planToConflictChannelRequests now includes channels
  with credentialAvailable=true and no hash, falling through to unknown-token
  conservative detection
- Fix cross-channel hash contamination: getCredentialHashesFromPlan now accepts
  an optional channelId filter; conflictReasonForRequest and
  conflictReasonForPair use the new resolveChannelHashesFromEntry helper so
  Slack or Discord hashes cannot produce false positive unknown-token results
  when checking a Telegram request
- Fix legacy hash fallback: when a plan-backed entry exists but carries no
  credentialHash for the requested channel (migration in flight), fall back to
  providerCredentialHashes so matching-token detection is not silently lost
- Align active-channel semantics with plan-filter.ts: getActiveChannelIdsFromPlan
  now also checks channel.active && !channel.disabled, not only disabledChannels
- Split plan-driven tests into src/lib/messaging/applier/conflict-detection.test.ts
  to offset the messaging-conflict.test.ts monolith growth; adds WhatsApp no-op
  test, cross-channel isolation, credentialAvailable-gate, and legacy-fallback cases

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 7, 2026
Base automatically changed from feat/persist-messaging-plan-in-session to main June 7, 2026 12:32
sandl99 and others added 3 commits June 7, 2026 18:58
…e and populate credentialHash in plan bindings

Remove hardcoded PROVIDER_SUFFIXES/KNOWN_CHANNEL_IDS from conflict-detection.ts; backfillLegacyEntryChannels now receives the suffix map as an injected parameter. The adapter layer (messaging-conflict.ts) derives it from BUILT_IN_CHANNEL_MANIFESTS credentials so adding a channel to the manifest registry propagates automatically.

Also fix credential-binding-engine to hash the env var value into credentialHash when credentialAvailable is true, enabling matching-token conflict detection on the plan-driven path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sandl99 sandl99 marked this pull request as ready for review June 7, 2026 14:53
@sandl99 sandl99 assigned sandl99 and unassigned sandl99 Jun 7, 2026
@sandl99 sandl99 added refactor PR restructures code without intended behavior change area: messaging Messaging channels, bridges, manifests, or channel lifecycle area: providers Inference provider integrations and provider behavior v0.0.61 Release target and removed v0.0.61 Release target labels Jun 7, 2026
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)
src/lib/messaging/applier/conflict-detection.test.ts (1)

59-70: 💤 Low value

Simplify redundant boolean expression.

Line 67 contains hash !== undefined || true, which always evaluates to true. This is logically correct but unnecessarily complex. Since tests that need credentialAvailable: false explicitly override it (line 195), and tests needing credentialAvailable: true with no hash also override it (line 176), consider simplifying to just credentialAvailable: true for clarity.

♻️ Proposed simplification
 function tgBinding(hash?: string): SandboxMessagingPlan["credentialBindings"][number] {
   return {
     channelId: "telegram",
     credentialId: "telegramBotToken",
     sourceInput: "botToken",
     providerName: "sb-telegram-bridge",
     providerEnvKey: "TELEGRAM_BOT_TOKEN",
     placeholder: "openshell:resolve:env:TELEGRAM_BOT_TOKEN",
-    credentialAvailable: hash !== undefined || true,
+    credentialAvailable: true,
     ...(hash !== undefined ? { credentialHash: hash } : {}),
   };
 }
🤖 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/applier/conflict-detection.test.ts` around lines 59 - 70,
The helper tgBinding currently sets credentialAvailable using the redundant
expression `hash !== undefined || true`; replace that with the simple literal
`credentialAvailable: true` in the tgBinding function so the value is explicit
and clearer (tests that need false/true already override credentialAvailable
where needed).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/onboard.ts`:
- Around line 2882-2884: The reuse path currently returns after
upsertMessagingProviders() and never applies extraPlaceholderKeys from
registerExtraPlaceholderProviders(sandboxName,...), so Brave Search (and similar
providers) are registered in the gateway but the sandbox env never receives the
placeholder declarations; fix by adding a reuse-time update: after
upsertMessagingProviders() in the ready-sandbox reuse branch, if
extraPlaceholderKeys.length > 0 either call the same sandbox-env update routine
used by create (e.g. the function that writes env vars/placeholders — add/update
sandbox env variables) to merge extraPlaceholderKeys into the sandbox
environment, or if no such update routine exists, treat non-empty
extraPlaceholderKeys as rebuild drift and force a sandbox rebuild/recreate
instead of returning early; reference extraPlaceholderKeys,
registerExtraPlaceholderProviders and upsertMessagingProviders when locating
where to apply this change.

---

Nitpick comments:
In `@src/lib/messaging/applier/conflict-detection.test.ts`:
- Around line 59-70: The helper tgBinding currently sets credentialAvailable
using the redundant expression `hash !== undefined || true`; replace that with
the simple literal `credentialAvailable: true` in the tgBinding function so the
value is explicit and clearer (tests that need false/true already override
credentialAvailable where needed).
🪄 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: c3dd64f4-8cd7-4ddc-955a-7c53b8aa680a

📥 Commits

Reviewing files that changed from the base of the PR and between 6913199 and 50bbc4e.

📒 Files selected for processing (6)
  • src/lib/messaging-conflict.test.ts
  • src/lib/messaging-conflict.ts
  • src/lib/messaging/applier/conflict-detection.test.ts
  • src/lib/messaging/applier/conflict-detection.ts
  • src/lib/messaging/compiler/engines/credential-binding-engine.ts
  • src/lib/onboard.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/messaging-conflict.test.ts
  • src/lib/messaging-conflict.ts

sandl99 and others added 2 commits June 7, 2026 21:49
…rison and add no-plan fallback

Address second round of PR Review Advisor findings:

- conflictReasonForRequest and conflictReasonForPair now use manifest-declared
  CHANNEL_CREDENTIAL_ENV_KEYS as the primary comparison set. For multi-credential
  channels like Slack (SLACK_BOT_TOKEN + SLACK_APP_TOKEN), a differing bot token
  with a missing app token previously returned null; it now returns unknown-token
  because the missing manifest key marks the comparison as incomplete.

- onboard.ts conflict gate: when hasPlanCredentials is false but token-backed
  channels were selected (enabledChannels contains non-QR channels), fall back to
  findChannelConflicts with just the channel names to preserve conservative
  unknown-token warnings even when the compiled plan has no credential data
  (e.g. credential-store-backed availability or stale env plan).

- policy-channel.ts: add explicit comment scoping the add-channel path as a
  known limitation — no compiled plan is available at channels-add time, so
  findChannelConflicts is used with caller-built hashes; plan-driven migration
  is follow-up work.

- Tests: four Slack partial-hash suppression cases covering the false-negative
  regression (conflictReasonForRequest with missing app token, both differ,
  conflictReasonForPair with missing app token from both sides, both differ).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…nifest-driven hashing

Address third round of PR Review Advisor findings:

- messaging-conflict.ts: add findChannelConflictsForOnboarding() that unions
  the plan-based hash-precise check with a channel-name-only fallback for any
  selectedTokenChannels not covered by the plan's credentialAvailable bindings.
  This ensures a partial or stale same-sandbox plan cannot silently skip channels
  it omits. onboard.ts now delegates to this single function rather than
  inlining the union logic.

- onboard.ts conflict gate: replace the multi-branch plan/fallback block with a
  single call to findChannelConflictsForOnboarding(sandboxName, currentPlan,
  selectedTokenChannels, registry), keeping all conflict logic in messaging-conflict.ts.

- policy-channel.ts checkChannelAddConflict: replace raw acquired-map iteration
  with manifest-driven hash building via createBuiltInChannelManifestRegistry().
  Iterates channelManifest.credentials[].providerEnvKey to build credentialHashes,
  mirroring planToConflictChannelRequests without requiring a compiled plan.
  QR-only channels (WhatsApp: credentials=[]) exit early with no conflict possible.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
sandl99 and others added 8 commits June 7, 2026 22:29
…tection

Legacy entries no longer carry hash metadata into conflict comparisons.
resolveChannelHashesFromEntry returns {} for entries without a plan, which
falls through to conservative unknown-token detection in all callers.

- ConflictRegistryEntry: drop providerCredentialHashes field
- resolveChannelHashesFromEntry: plan path only; legacy entries → {}
- CHANNEL_CREDENTIAL_ENV_KEYS comment updated (now solely for manifest-key
  comparison set, not legacy scoping)
- Section comment: "plan-preferred, legacy-fallback" → "Entry resolution"

- Remove findChannelConflictsForOnboarding and fallback logic; onboard.ts
  calls findChannelConflictsFromPlan directly (rationale in issue #4392)

Test updates:
- conflict-detection-entry.test.ts: remove legacy cross-channel hash scoping
  describe block; migrate Slack pair tests from providerCredentialHashes
  fixtures to plan-backed entries
- messaging-conflict.test.ts: remove hash-comparison tests (covered by
  plan-entry tests); update remaining fixtures to drop providerCredentialHashes;
  update file header comment

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…aths

Completes the providerCredentialHashes deprecation started in the phase
4a conflict-detection migration. The field was written by onboard.ts,
policy-channel.ts, and rebuild.ts, and read by messaging-credentials.ts
and workflow-planner.ts for rotation detection and credential-availability
inference.

All write paths are removed. Reads are replaced with plan-backed
equivalents: detectMessagingCredentialRotation now reads
credentialBindings.credentialHash from the compiled SandboxMessagingPlan,
and credentialAvailabilityFromSandboxEntry reads
plan.credentialBindings[].credentialAvailable. The field is removed from
SandboxEntry and MessagingWorkflowPlannerSandboxEntry entirely; existing
sandboxes.json files with stale providerCredentialHashes entries are
unaffected at runtime (unknown JSON fields are ignored).

Tests updated to use plan-backed fixtures for matching-token conflict
scenarios; credential-rotation tests use messaging.plan.credentialBindings
fixtures.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…-messaging

Both files shrank after removing providerCredentialHashes fixtures and
assertions in the preceding refactor commit.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Take nemoclaw-start budget reduction from main (5310→5300) and keep
onboard-messaging reduction from this branch (2122→2110).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@sandl99 sandl99 marked this pull request as ready for review June 8, 2026 03:01
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.

Caution

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

⚠️ Outside diff range comments (1)
src/lib/onboard.ts (1)

2777-2787: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't gate plan-driven conflict detection on credentialAvailable.

This skips findChannelConflictsFromPlan() entirely unless at least one binding already has a resolved hash. That drops the conservative unknown-token warning path for plans that enable token-backed channels but could not resolve hashes yet, so a conflicting sandbox can slip past pre-commit checks.

Suggested change
-  const hasPlanCredentials = currentPlan?.credentialBindings.some((b) => b.credentialAvailable) ?? false;
-  if (hasPlanCredentials) {
+  if (currentPlan) {
     const { backfillMessagingChannels, findChannelConflictsFromPlan, createMessagingConflictProbe } =
       require("./messaging/applier") as typeof import("./messaging/applier");

If you want to keep a fast path, gate on whether the plan yields any active conflict requests, not on whether a hash is already present. As per coding guidelines, src/lib/onboard.ts changes affect the full sandbox creation and configuration flow.

🤖 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.ts` around lines 2777 - 2787, The code currently skips
calling backfillMessagingChannels and findChannelConflictsFromPlan when
hasPlanCredentials (computed from currentPlan?.credentialBindings.some(b =>
b.credentialAvailable)) is false, which suppresses conservative unknown-token
conflict detection; change the gating so conflict detection runs regardless of
credentialAvailable — either remove the hasPlanCredentials conditional and
always construct the probe and call backfillMessagingChannels(registry, probe)
and findChannelConflictsFromPlan(sandboxName, currentPlan!, registry), or
replace the condition with a check that the plan actually declares any
token-backed channel requests (not whether hashes are already resolved) so that
findChannelConflictsFromPlan and createMessagingConflictProbe (and their
dependencies runOpenshell and providerExistsInGateway) still execute when the
plan could yield conflicts.

Source: Coding guidelines

🧹 Nitpick comments (1)
src/lib/onboard.ts (1)

2779-2809: Run the onboarding E2E slice before merge.

This file now changes both messaging conflict checks and resume-state bookkeeping. I'd run at least cloud-e2e, sandbox-operations-e2e, channels-stop-start-e2e, messaging-compatible-endpoint-e2e, and issue-3600-gpu-proof-optional-e2e on this branch.

As per coding guidelines, src/lib/onboard.ts contains core onboarding logic and the listed E2Es are the recommended selective coverage.

Also applies to: 5794-5799, 6053-6099, 6365-6383

🤖 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.ts` around lines 2779 - 2809, The onboarding change touches
messaging conflict checks (createMessagingConflictProbe,
backfillMessagingChannels, findChannelConflictsFromPlan and related calls like
runOpenshell and providerExistsInGateway) and resume-state bookkeeping; before
merging, run the onboarding E2E slice and the specific tests listed (cloud-e2e,
sandbox-operations-e2e, channels-stop-start-e2e,
messaging-compatible-endpoint-e2e, issue-3600-gpu-proof-optional-e2e) to
validate behavior, fix any failures uncovered (adjust probe logic, conflict
messaging, or resume-state handling), and add/adjust E2E coverage where missing
to ensure backfillMessagingChannels, conflict reporting,
promptYesNoOrDefault/isNonInteractive flows, and cliName guidance behave
correctly under CI.

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/onboard.ts`:
- Around line 2777-2787: The code currently skips calling
backfillMessagingChannels and findChannelConflictsFromPlan when
hasPlanCredentials (computed from currentPlan?.credentialBindings.some(b =>
b.credentialAvailable)) is false, which suppresses conservative unknown-token
conflict detection; change the gating so conflict detection runs regardless of
credentialAvailable — either remove the hasPlanCredentials conditional and
always construct the probe and call backfillMessagingChannels(registry, probe)
and findChannelConflictsFromPlan(sandboxName, currentPlan!, registry), or
replace the condition with a check that the plan actually declares any
token-backed channel requests (not whether hashes are already resolved) so that
findChannelConflictsFromPlan and createMessagingConflictProbe (and their
dependencies runOpenshell and providerExistsInGateway) still execute when the
plan could yield conflicts.

---

Nitpick comments:
In `@src/lib/onboard.ts`:
- Around line 2779-2809: The onboarding change touches messaging conflict checks
(createMessagingConflictProbe, backfillMessagingChannels,
findChannelConflictsFromPlan and related calls like runOpenshell and
providerExistsInGateway) and resume-state bookkeeping; before merging, run the
onboarding E2E slice and the specific tests listed (cloud-e2e,
sandbox-operations-e2e, channels-stop-start-e2e,
messaging-compatible-endpoint-e2e, issue-3600-gpu-proof-optional-e2e) to
validate behavior, fix any failures uncovered (adjust probe logic, conflict
messaging, or resume-state handling), and add/adjust E2E coverage where missing
to ensure backfillMessagingChannels, conflict reporting,
promptYesNoOrDefault/isNonInteractive flows, and cliName guidance behave
correctly under CI.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 557fd409-bfb3-45cf-9fe2-82d24983069f

📥 Commits

Reviewing files that changed from the base of the PR and between 7bee701 and 3634df4.

📒 Files selected for processing (23)
  • ci/test-file-size-budget.json
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/inventory/index.ts
  • src/lib/messaging-conflict.ts
  • src/lib/messaging/applier/conflict-detection-entry.test.ts
  • src/lib/messaging/applier/conflict-detection-legacy.test.ts
  • src/lib/messaging/applier/conflict-detection-plan.test.ts
  • src/lib/messaging/applier/conflict-detection.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/onboard.ts
  • src/lib/onboard/messaging-credentials.ts
  • src/lib/state/registry.ts
  • src/lib/status-command-deps.ts
  • test/channels-add-preset.test.ts
  • test/channels-remove-full-teardown.test.ts
  • test/cli/status-health.test.ts
  • test/credential-rotation.test.ts
  • test/e2e/test-token-rotation.sh
  • test/onboard-messaging.test.ts
  • test/rebuild-credential-preflight.test.ts
💤 Files with no reviewable changes (9)
  • src/lib/inventory/index.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • test/rebuild-credential-preflight.test.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/messaging-conflict.ts
  • src/lib/state/registry.ts
  • test/channels-remove-full-teardown.test.ts
  • test/onboard-messaging.test.ts
  • test/channels-add-preset.test.ts
✅ Files skipped from review due to trivial changes (2)
  • src/lib/status-command-deps.ts
  • ci/test-file-size-budget.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/messaging/applier/conflict-detection-plan.test.ts

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 8, 2026

Selective E2E Results — ❌ Some jobs failed

Run: 27115849905
Target ref: feat/phase-4a-messaging-conflict-plan-driven
Requested jobs: all (no filter)
Summary: 56 passed, 8 failed, 2 skipped

Job Result
agent-turn-latency-e2e ✅ success
bedrock-runtime-compatible-anthropic-e2e ✅ success
brave-search-e2e ✅ success
channels-add-remove-e2e ❌ failure
channels-stop-start-e2e ❌ failure
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
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 ❌ failure
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 ❌ failure
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 ❌ failure
rebuild-hermes-stale-base-e2e ❌ failure
rebuild-openclaw-e2e ❌ failure
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 ❌ failure
vm-driver-privileged-exec-routing-e2e ✅ success

Failed jobs: channels-add-remove-e2e, channels-stop-start-e2e, hermes-discord-e2e, messaging-providers-e2e, rebuild-hermes-e2e, rebuild-hermes-stale-base-e2e, rebuild-openclaw-e2e, upgrade-stale-sandbox-e2e. Check run artifacts for logs.

@sandl99 sandl99 requested a review from cv June 8, 2026 04:50
@sandl99 sandl99 added the v0.0.61 Release target label Jun 8, 2026
@sandl99
Copy link
Copy Markdown
Contributor Author

sandl99 commented Jun 8, 2026

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 8, 2026

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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)
src/lib/actions/sandbox/policy-channel.ts (1)

401-403: ⚡ Quick win

Use the existing module-level registry instead of creating a new instance.

messagingManifestRegistry is already defined at module scope (line 73) and used by resolveChannelManifest(). Creating a new registry here is redundant and inconsistent with the rest of the file.

♻️ Suggested fix
-  const channelManifest = createBuiltInChannelManifestRegistry()
-    .list()
-    .find((m) => m.id === channelName);
+  const channelManifest = messagingManifestRegistry.get(channelName);
🤖 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 401 - 403, The code
creates a new registry via createBuiltInChannelManifestRegistry() to find
channelManifest; instead use the existing module-level messagingManifestRegistry
(already used by resolveChannelManifest()) to avoid redundancy and keep
consistency—replace the createBuiltInChannelManifestRegistry().list().find(...)
lookup with a lookup against messagingManifestRegistry (e.g., use its
.list()/.find() or its existing resolver method) so channelManifest is obtained
from the shared messagingManifestRegistry.
🤖 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/applier/conflict-detection-entry.ts`:
- Around line 94-95: Zero-key credential comparisons in the
conflict-detection-entry logic are currently treated as "unknown-token", which
causes false conflicts for credential-less channels. Update both branches that
return "unknown-token" when keys.length === 0 so that the no-credential case is
handled as a no-op/non-conflicting result instead of producing a synthetic
token; make the same change in both occurrences called out in this file so
overlap/conflict detection skips channels with no comparison keys.

---

Nitpick comments:
In `@src/lib/actions/sandbox/policy-channel.ts`:
- Around line 401-403: The code creates a new registry via
createBuiltInChannelManifestRegistry() to find channelManifest; instead use the
existing module-level messagingManifestRegistry (already used by
resolveChannelManifest()) to avoid redundancy and keep consistency—replace the
createBuiltInChannelManifestRegistry().list().find(...) lookup with a lookup
against messagingManifestRegistry (e.g., use its .list()/.find() or its existing
resolver method) so channelManifest is obtained from the shared
messagingManifestRegistry.
🪄 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: d04c186f-f936-4a91-8eab-64d19e66296a

📥 Commits

Reviewing files that changed from the base of the PR and between 7bee701 and be2bbe0.

📒 Files selected for processing (31)
  • ci/test-file-size-budget.json
  • src/lib/actions/sandbox/policy-channel-conflict.test.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/inventory/index.ts
  • src/lib/messaging-conflict.ts
  • src/lib/messaging/applier/conflict-detection-backfill.ts
  • src/lib/messaging/applier/conflict-detection-entry.test.ts
  • src/lib/messaging/applier/conflict-detection-entry.ts
  • src/lib/messaging/applier/conflict-detection-legacy.test.ts
  • src/lib/messaging/applier/conflict-detection-manifest.ts
  • src/lib/messaging/applier/conflict-detection-multi-credential.test.ts
  • src/lib/messaging/applier/conflict-detection-overlap.test.ts
  • src/lib/messaging/applier/conflict-detection-plan.test.ts
  • src/lib/messaging/applier/conflict-detection-plan.ts
  • src/lib/messaging/applier/conflict-detection-types.ts
  • src/lib/messaging/applier/conflict-detection.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/onboard.ts
  • src/lib/onboard/messaging-credentials.ts
  • src/lib/state/registry.ts
  • src/lib/status-command-deps.ts
  • test/channels-add-preset.test.ts
  • test/channels-remove-full-teardown.test.ts
  • test/cli/status-health.test.ts
  • test/credential-rotation.test.ts
  • test/e2e/test-token-rotation.sh
  • test/helpers/messaging-conflict-fixtures.ts
  • test/onboard-messaging.test.ts
  • test/rebuild-credential-preflight.test.ts
💤 Files with no reviewable changes (9)
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/messaging-conflict.ts
  • test/channels-remove-full-teardown.test.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • test/rebuild-credential-preflight.test.ts
  • test/onboard-messaging.test.ts
  • src/lib/inventory/index.ts
  • test/channels-add-preset.test.ts
  • src/lib/state/registry.ts
✅ Files skipped from review due to trivial changes (1)
  • ci/test-file-size-budget.json

Comment thread src/lib/messaging/applier/conflict-detection-entry.ts Outdated
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Jun 8, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 8, 2026

Selective E2E Results — ✅ All requested jobs passed

Run: 27118468378
Target ref: feat/phase-4a-messaging-conflict-plan-driven
Requested jobs: channels-stop-start-e2e,channels-add-remove-e2e,upgrade-stale-sandbox-e2e,hermes-discord-e2e,rebuild-openclaw-e2e,rebuild-hermes-stale-base-e2e,rebuild-hermes-e2e,messaging-providers-e2e
Summary: 8 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success
channels-stop-start-e2e ✅ success
hermes-discord-e2e ✅ success
messaging-providers-e2e ✅ success
rebuild-hermes-e2e ✅ success
rebuild-hermes-stale-base-e2e ✅ success
rebuild-openclaw-e2e ✅ success
upgrade-stale-sandbox-e2e ✅ success

Signed-off-by: San Dang <sdang@nvidia.com>
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 area: providers Inference provider integrations and provider behavior refactor PR restructures code without intended behavior change v0.0.61 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 4a: migrate messaging credential conflict detection to manifest plans

3 participants