Skip to content

fix: #80507 show dry-run output for message send/poll#94684

Merged
clawsweeper[bot] merged 1 commit into
openclaw:mainfrom
lzyyzznl:fix/issue-80507-dry-run-output
Jun 19, 2026
Merged

fix: #80507 show dry-run output for message send/poll#94684
clawsweeper[bot] merged 1 commit into
openclaw:mainfrom
lzyyzznl:fix/issue-80507-dry-run-output

Conversation

@lzyyzznl

Copy link
Copy Markdown
Contributor

Summary

When openclaw message send --dry-run is used, the pretty-text CLI output incorrectly prints ✅ Sent via <channel>. Message ID: unknown — the same success message as a real send. The formatter checks result.handledBy === "dry-run", but the send/poll execution path (executeSendAction) always returns handledBy: "core" with a separate dryRun: true flag, so the dry-run branch is dead code.

The fix changes the condition from result.handledBy === "dry-run" to result.dryRun. All four variants of MessageActionRunResult (send, broadcast, poll, action) include the required dryRun: boolean field, making this a type-safe single-line fix.

Fixes #80507

Real behavior proof

Behavior addressed: Fix openclaw message send --dry-run (and the equivalent poll path) so the pretty-text CLI output shows a muted [dry-run] would run send via <channel> line instead of incorrectly printing ✅ Sent via <channel>. Message ID: unknown.

Real environment tested: Linux 6.8.0-124-generic x64 / OpenClaw 2026.6.8 (built from source at a8d60d3) / Node.js v25.9.0

Exact steps or command run after this patch:

# 1. Run message send with --dry-run (pretty-text output)
node openclaw.mjs message send --channel slack --target "channel:test123" --message "qa probe" --dry-run

# 2. Verify the JSON output confirms dryRun was honored
node openclaw.mjs message send --channel slack --target "channel:test123" --message "qa probe" --dry-run --json

After-fix evidence:

$ node openclaw.mjs message send --channel slack --target "channel:test123" --message "qa probe" --dry-run
[dry-run] would run send via slack

$ node openclaw.mjs message send --channel slack --target "channel:test123" --message "qa probe" --dry-run --json
{
  "action": "send",
  "channel": "slack",
  "dryRun": true,
  "handledBy": "core",
  "payload": {
    "channel": "slack",
    "to": "test123",
    "via": "direct",
    "mediaUrl": null,
    "dryRun": true
  }
}

Observed result after the fix: The pretty-text output now correctly prints [dry-run] would run send via slack (muted style) instead of the old buggy ✅ Sent via Slack. Message ID: unknown. The --json output confirms dryRun: true and handledBy: "core" — proving the fix correctly checks result.dryRun rather than the never-set result.handledBy === "dry-run".

What was not tested: The broadcast dry-run path (kind: "broadcast" with handledBy: "dry-run") was not explicitly tested, but the type-safe change preserves existing behavior for broadcast since dryRun is also present on that variant.

Tests and validation

Type safety

The MessageActionRunResult union type guarantees correctness:

// All four variants have dryRun: boolean (required, not optional):
type MessageActionRunResult =
  | { kind: "send";    handledBy: "plugin" | "core" | "internal-source"; dryRun: boolean; ... }
  | { kind: "broadcast"; handledBy: "core" | "dry-run";                   dryRun: boolean; ... }
  | { kind: "poll";    handledBy: "plugin" | "core";                      dryRun: boolean; ... }
  | { kind: "action";  handledBy: "plugin" | "dry-run";                  dryRun: boolean; ... }
  • kind: "send"handledBy is never "dry-run" (was dead code)
  • kind: "poll"handledBy is never "dry-run" (was dead code)
  • kind: "broadcast" and kind: "action"handledBy CAN be "dry-run", but dryRun is also present and truthy — behavior preserved

The fix moves from checking a value that can never be "dry-run" on the send/poll path (handledBy) to checking the field that correctly indicates dry-run state (dryRun).

Build verification

$ pnpm build cliStartup
[build-all] phase timings: total 18.3s; slowest write-cli-startup-metadata 12.4s; tsdown 4.83s
Build succeeded with no errors.

Risk checklist

  • This change is backwards compatible
  • This change has been tested with existing configurations
  • I have updated relevant documentation (N/A — no behavior contract change)
  • Breaking changes (if any) are documented in Summary (N/A)

Current review state

  • Self-review completed
  • At least one maintainer review
  • All CI checks passed

@openclaw-barnacle openclaw-barnacle Bot added commands Command implementations size: XS proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 18, 2026
@clawsweeper

clawsweeper Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Codex review: passed. Reviewed June 18, 2026, 11:50 PM ET / 03:50 UTC.

Summary
The branch changes formatMessageCliText to render dry-run message output from result.dryRun instead of only handledBy === "dry-run".

PR surface: Source 0. Total 0 across 1 file.

Reproducibility: yes. source-reproducible. The linked issue has captured CLI output, and current main shows send/poll results carry dryRun separately while the formatter still checks handledBy === "dry-run"; I did not execute the CLI in this read-only review.

Review metrics: 1 noteworthy metric.

  • Open fix candidates: 2 open closing PRs. Both open PRs target the same dry-run formatter bug, so maintainers should land one path and close or supersede the other.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #80507
Summary: This PR is a candidate fix for the canonical dry-run CLI formatter bug; one sibling open PR targets the same predicate with tests but lacks sufficient real behavior proof.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Add or carry focused send/poll formatter regression tests if maintainers want durable coverage before merge.

Risk before merge

  • [P1] This branch does not add a committed formatter regression test; maintainers may choose to carry tests from fix(message): show dry-run output for send/poll #80604 before or after landing.
  • [P1] A sibling open PR targets the same canonical bug, so one fix candidate should be superseded after one lands.

Maintainer options:

  1. Decide the mitigation before merge
    Land one dryRun-based formatter fix, with this PR as the proof-positive candidate, then close [Bug]: openclaw message send --dry-run prints ✅ Sent via <channel>. Message ID: unknown — pretty-text formatter never sees handledBy: "dry-run" and falls through to the success message #80507 and supersede fix(message): show dry-run output for send/poll #80604.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P2] No repair job is needed; the remaining work is maintainer/automerge handling and duplicate cleanup after one fix lands.

Security
Cleared: The diff is a one-line CLI formatter predicate change and does not touch dependencies, workflows, scripts, permissions, secrets, network calls, or package metadata.

Review details

Best possible solution:

Land one dryRun-based formatter fix, with this PR as the proof-positive candidate, then close #80507 and supersede #80604.

Do we have a high-confidence way to reproduce the issue?

Yes, source-reproducible. The linked issue has captured CLI output, and current main shows send/poll results carry dryRun separately while the formatter still checks handledBy === "dry-run"; I did not execute the CLI in this read-only review.

Is this the best way to solve the issue?

Yes. Checking result.dryRun in the formatter is the narrow maintainable fix because send and poll already skip delivery and carry dry-run state separately; changing outbound handledBy semantics would broaden the runner contract unnecessarily.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 36bfe77db19c.

Label changes

Label changes:

  • add status: 🚀 automerge armed: This PR is in ClawSweeper's automerge lane. Sufficient (terminal): The PR body includes after-fix terminal output from a patched real CLI send dry-run plus JSON confirming dryRun: true; poll was not separately run but uses the same formatter guard.
  • remove status: 👀 ready for maintainer look: Current PR status label is status: 🚀 automerge armed.

Label justifications:

  • P2: This is a normal-priority CLI correctness fix: dry-run output can mislead users and scripts, but delivery is still skipped and the runtime does not crash.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 🚀 automerge armed: This PR is in ClawSweeper's automerge lane. Sufficient (terminal): The PR body includes after-fix terminal output from a patched real CLI send dry-run plus JSON confirming dryRun: true; poll was not separately run but uses the same formatter guard.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal output from a patched real CLI send dry-run plus JSON confirming dryRun: true; poll was not separately run but uses the same formatter guard.
Evidence reviewed

PR surface:

Source 0. Total 0 across 1 file.

View PR surface stats
Area Files Added Removed Net
Source 1 1 1 0
Tests 0 0 0 0
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 1 1 1 0

What I checked:

Likely related people:

  • steipete: GitHub path history shows repeated recent work on the message formatter, message command, and outbound runner surfaces that define this CLI output boundary. (role: feature-history owner; confidence: high; commits: c6a6f56699b4, 00d8d7ead059, 396768304979; files: src/commands/message-format.ts, src/commands/message.ts, src/infra/outbound/message-action-runner.ts)
  • vincentkoc: Blame on the current formatter block and recent outbound history show work on the result-shape and dry-run-adjacent paths that feed this formatter. (role: recent area contributor; confidence: high; commits: 8c3185d55c82, a22a1edc8faa, 6a0fdea90ad0; files: src/commands/message-format.ts, src/infra/outbound/message-action-runner.ts, src/infra/outbound/outbound-send-service.ts)
  • shakkernerd: Recent path history includes formatter-summary work on the same CLI presentation file touched by this PR. (role: recent formatter contributor; confidence: medium; commits: 8fe449c8834b; files: src/commands/message-format.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels Jun 18, 2026
@vincentkoc

Copy link
Copy Markdown
Member

/clownfish automerge

@vincentkoc vincentkoc added the clownfish:automerge Maintainer opted this Clownfish PR into bounded ClawSweeper-reviewed automerge label Jun 19, 2026
@vincentkoc

Copy link
Copy Markdown
Member

Clownfish is on the reef for this PR. 🐠

I tagged clownfish:automerge and sent ClawSweeper over this exact head. If the sweep finds rough coral, failing checks, or needs-human, I will take another bounded repair lap and ask for a fresh review.

A maintainer can call /clownfish stop any time and I will drift this back to human review.

@lzyyzznl

Copy link
Copy Markdown
Contributor Author

Clownfish is on the reef for this PR. 🐠

I tagged clownfish:automerge and sent ClawSweeper over this exact head. If the sweep finds rough coral, failing checks, or needs-human, I will take another bounded repair lap and ask for a fresh review.

A maintainer can call /clownfish stop any time and I will drift this back to human review.

Thank you. I will continue to follow this.

@vincentkoc

Copy link
Copy Markdown
Member

/clownfish automerge

@vincentkoc vincentkoc added the clawsweeper:automerge Maintainer opted this PR into bounded ClawSweeper-reviewed automerge label Jun 19, 2026
@vincentkoc

Copy link
Copy Markdown
Member

Clownfish is on the reef for this PR. 🐠

I tagged clownfish:automerge and sent ClawSweeper over this exact head. If the sweep finds rough coral, failing checks, or needs-human, I will take another bounded repair lap and ask for a fresh review.

A maintainer can call /clownfish stop any time and I will drift this back to human review.

@clawsweeper clawsweeper Bot added status: 🚀 automerge armed This PR is in ClawSweeper's automerge lane. and removed status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 19, 2026
@clawsweeper
clawsweeper Bot merged commit 508e3bf into openclaw:main Jun 19, 2026
249 of 255 checks passed
@clawsweeper

clawsweeper Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

🦞✅
ClawSweeper merged this PR after the passing review.

Source: clawsweeper[bot]
Feedback: structured ClawSweeper verdict: pass (sha=dce6d6a0d3831b62e896b9de04639a8c8d1f8741)
Merge status: merged by ClawSweeper automerge
Merged at: 2026-06-19T03:51:51Z
Merge commit: 508e3bf41353

What merged:

  • The branch changes formatMessageCliText to render dry-run message output from result.dryRun instead of only handledBy === "dry-run".
  • PR surface: Source 0. Total 0 across 1 file.
  • Reproducibility: yes. source-reproducible. The linked issue has captured CLI output, and current main shows ... e the formatter still checks handledBy === "dry-run"; I did not execute the CLI in this read-only review.

Automerge notes:

  • No ClawSweeper repair was needed after automerge opt-in.

The automerge loop is complete.

Automerge progress:

  • 2026-06-19 03:51:22 UTC review passed dce6d6a0d383 (structured ClawSweeper verdict: pass (sha=dce6d6a0d3831b62e896b9de04639a8c8d1f8...)
  • 2026-06-19 03:51:54 UTC merged dce6d6a0d383 (merged by ClawSweeper automerge)

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 19, 2026
…aw#94684)

Summary:
- The branch changes `formatMessageCliText` to render dry-run message output from `result.dryRun` instead of only `handledBy === "dry-run"`.
- PR surface: Source 0. Total 0 across 1 file.
- Reproducibility: yes. source-reproducible. The linked issue has captured CLI output, and current main shows  ... e the formatter still checks `handledBy === "dry-run"`; I did not execute the CLI in this read-only review.

Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.

Validation:
- ClawSweeper review passed for head dce6d6a.
- Required merge gates passed before the squash merge.

Prepared head SHA: dce6d6a
Review: openclaw#94684 (comment)

Co-authored-by: lizeyu-xydt <[email protected]>
cxbAsDev pushed a commit to cxbAsDev/openclaw that referenced this pull request Jun 23, 2026
…aw#94684)

Summary:
- The branch changes `formatMessageCliText` to render dry-run message output from `result.dryRun` instead of only `handledBy === "dry-run"`.
- PR surface: Source 0. Total 0 across 1 file.
- Reproducibility: yes. source-reproducible. The linked issue has captured CLI output, and current main shows  ... e the formatter still checks `handledBy === "dry-run"`; I did not execute the CLI in this read-only review.

Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.

Validation:
- ClawSweeper review passed for head dce6d6a.
- Required merge gates passed before the squash merge.

Prepared head SHA: dce6d6a
Review: openclaw#94684 (comment)

Co-authored-by: lizeyu-xydt <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clawsweeper:automerge Maintainer opted this PR into bounded ClawSweeper-reviewed automerge clownfish:automerge Maintainer opted this Clownfish PR into bounded ClawSweeper-reviewed automerge commands Command implementations P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS status: 🚀 automerge armed This PR is in ClawSweeper's automerge lane.

Projects

None yet

2 participants