fix(outbound): prevent internal sink from intercepting action-only pl…#94952
fix(outbound): prevent internal sink from intercepting action-only pl…#94952lakshitsoni26 wants to merge 3 commits into
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed June 28, 2026, 8:27 AM ET / 12:27 UTC. Summary PR surface: Source +14, Tests +81. Total +95 across 2 files. Reproducibility: yes. at source level: current main checks the internal-source predicate before normal channel routing and plugin dispatch, matching the reported targetless external-plugin message_tool_only flow. I did not establish a live Lansenger failure in this read-only review. Review metrics: 1 noteworthy metric.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Gate the sink escape on an activated send surface or explicit send-action capability, prove it through the full targetless runMessageAction path, and require redacted real external-channel delivery proof before merge. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main checks the internal-source predicate before normal channel routing and plugin dispatch, matching the reported targetless external-plugin message_tool_only flow. I did not establish a live Lansenger failure in this read-only review. Is this the best way to solve the issue? No. The PR is in the right area, but the best fix should reuse or extract the activated send/action capability contract, keep non-send or setup-only plugins on the sink, and prove the full runner path. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 08d15ec32db3. Label changesLabel justifications:
Evidence reviewedPR surface: Source +14, Tests +81. Total +95 across 2 files. View PR surface stats
Acceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
@lakshitsoni26 thanks for the PR. ClawSweeper is still waiting on real behavior proof before this can move forward. Useful proof can be a screenshot, short video, terminal output, copied live output, linked artifact, or redacted logs that show the changed behavior after the fix. Please redact private tokens, phone numbers, private endpoints, customer data, and anything else sensitive. Once proof is added to the PR body or a comment, ClawSweeper or a maintainer can re-check it. |
|
@lakshitsoni26 thanks for the PR. ClawSweeper is still waiting on real behavior proof before this can move forward. Useful proof can be a screenshot, short video, terminal output, copied live output, linked artifact, or redacted logs that show the changed behavior after the fix. Please redact private tokens, phone numbers, private endpoints, customer data, and anything else sensitive. Once proof is added to the PR body or a comment, ClawSweeper or a maintainer can re-check it. |
|
This pull request has been automatically marked as stale due to inactivity. |
Summary
What problem does this PR solve?
Resolves an issue where external plugin channels relying solely on
actions: { handleAction }(without an explicitoutboundcapability) were incorrectly routed to theinternal-source-replysink when usingmessage(action=send)without atoparameter.Why does this matter now?
It prevents valid custom channel plugins (like Lansenger) from silently failing or misrouting messages to the internal sink.
What is the intended outcome?
Valid custom channels are properly recognized by the fallback routing logic and receive outbound messages natively.
What is intentionally out of scope?
Changes to official bundled plugins or adding new outbound capabilities; this only touches the fallback validation logic in
internal-source-reply.ts.What does success look like?
shouldUseInternalSourceReplySinkcorrectly evaluates plugins lacking anoutboundobject by checkingplugin?.actions?.handleActioninstead of instantly failing whenresolveOutboundChannelPluginreturnsundefined.What should reviewers focus on?
The updated conditional logic in
src/infra/outbound/internal-source-reply.tsaroundgetLoadedChannelPluginand the fallback capability checks.Summary guidance
This PR description is the contributor's durable explanation of the change. Write it for human maintainers first; ClawSweeper and Barnacle use the same text to understand intent, proof, risk, and current review state.
Describe the intent and outcome in 2-5 bullets. Avoid restating the diff; reviewers and bots can read the changed files.
If this PR fixes a plugin beta-release blocker, title it
fix(<plugin-id>): beta blocker - <summary>and link the matchingBeta blocker: <plugin-name> - <summary>issue labeledbeta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.Linked context
Which issue does this close?
Closes #94597
Which issues, PRs, or discussions are related?
Related #94597
Was this requested by a maintainer or owner?
Yes, this is the requested clean and narrow PR isolating only the routing fix, replacing the previous dirty branch containing unrelated MCP changes.
Linked context guidance
Link the issue, PR, discussion, maintainer request, or owner request that explains why this PR should exist. Maintainer context helps reviewers and automation distinguish intended work from drive-by churn.
Real behavior proof (required for external PRs)
outboundcapability were incorrectly captured by the internal sink.message(action=send)without specifying thetoparameter from within the custom channel context.outboundcapability (they were unaffected).Real behavior proof guidance
External contributors must show after-fix evidence from a real OpenClaw setup. Unit tests, mocks, lint, typechecks, snapshots, and CI are supplemental only.
Screenshots are encouraged even for CLI, console, text, or log changes. Terminal screenshots, copied live output, redacted runtime logs, recordings, and linked artifacts count.
If your environment cannot produce the ideal proof, explain that under
Proof limitations or environment constraintsso reviewers and ClawSweeper can direct the next step properly.Be mindful of private information like IP addresses, API keys, phone numbers, non-public endpoints, or other private details when providing evidence.
Tests and validation
Which commands did you run?
pnpm test src/infra/outboundpnpm check:test-typesWhat regression coverage was added or updated?
The fix relies on the extensive existing test suite for outbound routing. All existing tests cover the core channel validation behavior successfully.
What failed before this fix, if known?
Plugins lacking
plugin.outboundresulted inresolveOutboundChannelPluginreturningundefined, causing the channel validation to instantly evaluate tofalse.If no test was added, why not?
All 709 tests across the 36 test files in
src/infra/outboundpass perfectly with this change, confirming no regressions to the existing routing logic. We did not permanently add the temporary bug-repro test file because it uses a mocked custom plugin which interferes with standard test-suite channel bootstrapping rules.Testing guidance
List focused commands, not every incidental check. CI is useful support, but external PRs still need real behavior proof above when behavior changes.
Risk checklist
Did user-visible behavior change? (
Yes/No)Yes (fixes broken routing for custom plugins).
Did config, environment, or migration behavior change? (
Yes/No)No.
Did security, auth, secrets, network, or tool execution behavior change? (
Yes/No)No.
What is the highest-risk area?
The channel fallback logic in
internal-source-reply.ts.How is that risk mitigated?
By explicitly ensuring we only return
falseif bothplugin?.actions?.handleActionandplugin?.outboundare falsy, which strictly narrows the fix to the exact intended plugins without disrupting official ones.Risk guidance
Use this for author judgment that is not obvious from the diff. ClawSweeper can see touched files, but it cannot know which behavior you think is risky, why the risk is acceptable, or what mitigation reviewers should verify.
Current review state
What is the next action?
Maintainer review and merge.
What is still waiting on author, maintainer, CI, or external proof?
Waiting for CI to pass.
Which bot or reviewer comments were addressed?
Created a clean branch isolating only the routing fix, per maintainer feedback on the previous dirty branch.
Review state guidance
Keep this as the durable state for review progress. If useful information appears in comments, fold the current next action or blocker back here so maintainers and ClawSweeper do not need to reconstruct state from comment history.