Skip to content

fix(slack): keep one draft message in progress mode#85612

Merged
steipete merged 1 commit into
openclaw:mainfrom
mycarrysun:fix/slack-progress-single-draft
May 31, 2026
Merged

fix(slack): keep one draft message in progress mode#85612
steipete merged 1 commit into
openclaw:mainfrom
mycarrysun:fix/slack-progress-single-draft

Conversation

@mycarrysun

@mycarrysun mycarrysun commented May 23, 2026

Copy link
Copy Markdown
Contributor

Summary

In channels.slack.streaming.mode = "progress" (internally status_final), Slack should keep one rolling draft preview and finalize that same message in place when the final reply lands. Multi-segment assistant turns were instead posting one draft per assistant/reasoning boundary because the boundary handler called draftStream.forceNewMessage(), clearing the draft messageId before the next update.

Fix

  • Keep status_final drafts on the same Slack message by skipping only the forceNewMessage() call in progress mode.
  • Preserve the existing boundary cleanup so reasoning/progress state does not leak across segments.
  • Preserve the last non-empty progress lines for both rich and text progress drafts, so a boundary-triggered status refresh does not erase the visible progress preview.
  • Keep partial/replace behavior unchanged: assistant boundaries still force a new draft message outside progress mode.

Verification

  • node scripts/run-vitest.mjs extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts extensions/slack/src/monitor/message-handler/dispatch.streaming.test.ts --reporter=dot
  • ./node_modules/.bin/oxfmt --check extensions/slack/src/monitor/message-handler/dispatch.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts
  • ./node_modules/.bin/oxlint --tsconfig ./tsconfig.json extensions/slack/src/monitor/message-handler/dispatch.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts
  • git diff --check
  • /Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode local

Real behavior proof

Behavior or issue addressed: In channels.slack.streaming.mode = "progress", a multi-segment assistant turn was posting one new draft message per assistant segment instead of editing one rolling preview in place. Earlier drafts were left as orphaned progress messages above the final reply.

Real environment tested: Production Slack workspace, real Slack bot identity via socket mode, OpenClaw agent running the patched bundle on the same EC2 host that reproduced the bug. Slack streaming config used channels.slack.streaming = { mode: "progress" } per account, with replies threaded.

Exact steps or command run after this patch: Built the patched Slack extension bundle, deployed it onto the production agent host, restarted the agent so Slack reconnected with the new dispatch wiring, then sent the same kind of tool-using Slack prompt that previously produced multiple progress messages. The channel was observed during streaming and after the final reply landed.

Evidence after fix: Before screenshot showed one turn producing multiple orphaned progress messages. After screenshot showed one rolling progress draft finalized in place, with no orphaned progress messages above the final reply. Evidence images: https://github.com/mycarrysun/openclaw/releases/download/slack-progress-proof/slack-progress-before.jpg and https://github.com/mycarrysun/openclaw/releases/download/slack-progress-proof/slack-progress-after.jpg.

Observed result after fix: The Slack channel showed exactly one draft preview message for the whole multi-segment turn. Assistant text and tool-progress updates edited that single message instead of posting new drafts, and the final reply finalized the same message.

What was not tested: Partial and block/replace streaming modes were not exercised against a live Slack workspace in this run; focused regression tests cover that those modes still force a new draft on assistant boundaries.

@openclaw-barnacle openclaw-barnacle Bot added channel: slack Channel integration: slack triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. size: S labels May 23, 2026
@clawsweeper

clawsweeper Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed May 31, 2026, 12:00 PM ET / 16:00 UTC.

Summary
The PR changes Slack progress-mode draft streaming so assistant/reasoning boundaries keep editing one rolling draft message, while partial/replace modes still start a fresh draft.

PR surface: Source +3, Tests +42. Total +45 across 2 files.

Reproducibility: yes. source-reproducible with supplied live proof: current main calls forceNewMessage at assistant/reasoning boundaries, and that clears the Slack draft message id so the next progress update sends a new message. I did not run a new live Slack reproduction from this checkout.

Review metrics: none identified.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster ✨ media proof bonus
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

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

Mantis proof suggestion
A Slack desktop smoke would provide exact-head visual confirmation of the user-visible delivery behavior if maintainers want more than the existing screenshots. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

slack desktop smoke: verify progress-mode Slack drafts stay on one rolling message across assistant boundaries and finalize that same message.

Risk before merge

Maintainer options:

  1. Resolve checks and merge ordering first (recommended)
    Confirm the current check failures are unrelated or fixed, then merge this PR in an order that preserves the focused Slack draft-boundary behavior if related Slack PRs land nearby.
  2. Accept the existing live proof
    Maintainers can decide the supplied production Slack screenshots plus focused tests are enough without a fresh live Slack run from the refreshed head.
  3. Ask for a fresh Slack smoke
    If maintainers want visual confirmation on the exact latest head, request a Slack desktop smoke that shows one rolling progress draft finalizing in place.

Next step before merge

  • No automated repair is indicated; maintainers should resolve or classify the current failing checks, account for nearby Slack dispatch PR overlap, and then land the focused PR if satisfied.

Security
Cleared: The diff only changes Slack dispatch logic and focused tests; it does not add dependencies, scripts, workflows, lockfile changes, secrets handling, or new code-execution surfaces.

Review details

Best possible solution:

Land the focused progress-mode guard after required checks are green or classified and any overlapping Slack dispatch PRs are reconciled, while keeping partial/replace draft-boundary behavior unchanged.

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

Yes, source-reproducible with supplied live proof: current main calls forceNewMessage at assistant/reasoning boundaries, and that clears the Slack draft message id so the next progress update sends a new message. I did not run a new live Slack reproduction from this checkout.

Is this the best way to solve the issue?

Yes. The PR is the narrowest maintainable fix I found: it skips only the progress-mode message-id reset, keeps boundary cleanup, and adds regression coverage that partial/replace mode still starts a new draft.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 29dd7847fd96.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The contributor supplied before/after production Slack screenshots that directly show the duplicate progress drafts before and one finalized message after; maintainer proof adds focused tests on the refreshed head.

Label justifications:

  • P2: This is a normal-priority Slack channel delivery bug affecting progress-mode draft previews, with a narrow patch and supplied proof.
  • merge-risk: 🚨 message-delivery: The diff controls whether Slack draft updates edit the existing message or post a new message, so merge safety depends on preserving the intended delivery behavior.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (screenshot): The contributor supplied before/after production Slack screenshots that directly show the duplicate progress drafts before and one finalized message after; maintainer proof adds focused tests on the refreshed head.
  • proof: sufficient: Contributor real behavior proof is sufficient. The contributor supplied before/after production Slack screenshots that directly show the duplicate progress drafts before and one finalized message after; maintainer proof adds focused tests on the refreshed head.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The contributor supplied before/after production Slack screenshots that directly show the duplicate progress drafts before and one finalized message after; maintainer proof adds focused tests on the refreshed head.
Evidence reviewed

PR surface:

Source +3, Tests +42. Total +45 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 5 2 +3
Tests 1 43 1 +42
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 48 3 +45

Acceptance criteria:

  • [P2] node scripts/run-vitest.mjs extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts extensions/slack/src/monitor/message-handler/dispatch.streaming.test.ts --reporter=dot.
  • [P2] ./node_modules/.bin/oxfmt --check extensions/slack/src/monitor/message-handler/dispatch.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts.
  • [P2] ./node_modules/.bin/oxlint --tsconfig ./tsconfig.json extensions/slack/src/monitor/message-handler/dispatch.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts.
  • [P1] git diff --check.

What I checked:

Likely related people:

  • steipete: Peter Steinberger is the heaviest sampled contributor in Slack dispatch/draft history, has recent commits around Slack thread/draft behavior, and supplied maintainer proof on this PR. (role: recent area contributor and reviewer; confidence: high; commits: e93216080aa1, 6b525023d4d2, eee37bf83634; files: extensions/slack/src/monitor/message-handler/dispatch.ts, extensions/slack/src/draft-stream.ts, extensions/slack/src/monitor/message-handler/preview-finalize.ts)
  • Steven: git blame attributes the current main dispatch.ts boundary and progress draft lines to commit 13d2800 in this grafted checkout, so Steven is a useful current-source routing signal even though deeper history is compressed. (role: current snapshot introducer; confidence: medium; commits: 13d2800489b1; files: extensions/slack/src/monitor/message-handler/dispatch.ts, extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts)
  • vincentkoc: Vincent Koc authored a recent historical Slack transport fix touching this area before the current grafted snapshot. (role: historical Slack channel contributor; confidence: medium; commits: e28b516fb5b3; files: extensions/slack/src/monitor/message-handler/dispatch.ts)
  • scoootscooob: scoootscooob moved Slack channel code into extensions/slack/src, which is relevant provenance for the current plugin boundary and file location. (role: Slack extension refactor contributor; confidence: low; commits: 8746362f5ebf; files: extensions/slack/src/monitor/message-handler/dispatch.ts, extensions/slack/src/draft-stream.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 rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels May 23, 2026
@clawsweeper

clawsweeper Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🥚 common Frosted Shellbean

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

Rarity: 🥚 common.
Trait: hums during re-review.
Image traits: location CI tidepool; accessory CI status badge; palette moss green and polished brass; mood celebratory; pose pointing at a small proof artifact; shell matte ceramic shell; lighting soft studio lighting; background tiny shells and proof notes.
Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Frosted Shellbean in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@mycarrysun mycarrysun closed this May 23, 2026
@mycarrysun

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

@clawsweeper

clawsweeper Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper could not start a re-review for this item.

Reason: re-review requires an open issue or PR.

@mycarrysun mycarrysun reopened this May 27, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 27, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. 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. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 27, 2026
@mycarrysun
mycarrysun force-pushed the fix/slack-progress-single-draft branch from 32c8b5b to fd7d44f Compare May 27, 2026 05:02
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 27, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 27, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 27, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 27, 2026
@mycarrysun
mycarrysun force-pushed the fix/slack-progress-single-draft branch from 05c24ca to 41e304a Compare May 27, 2026 05:29
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 27, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 27, 2026
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels May 27, 2026
@BingqingLyu

This comment was marked as spam.

@steipete steipete self-assigned this May 31, 2026
@steipete
steipete force-pushed the fix/slack-progress-single-draft branch from 41e304a to 947a719 Compare May 31, 2026 15:53
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@steipete

Copy link
Copy Markdown
Contributor

Maintainer proof on refreshed head 947a719:

Behavior addressed: Slack progress-mode drafts now stay on one rolling preview message across assistant/reasoning boundaries, while partial/replace modes still force a new draft at assistant boundaries.

Real environment tested: contributor's production Slack proof remains in the PR body; maintainer local proof covered the Slack dispatch boundary behavior on the refreshed head.

Exact steps or command run after this patch:

  • node scripts/run-vitest.mjs extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts extensions/slack/src/monitor/message-handler/dispatch.streaming.test.ts --reporter=dot
  • ./node_modules/.bin/oxfmt --check extensions/slack/src/monitor/message-handler/dispatch.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts
  • ./node_modules/.bin/oxlint --tsconfig ./tsconfig.json extensions/slack/src/monitor/message-handler/dispatch.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts
  • git diff --check
  • /Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode local

Evidence after fix: focused Vitest passed 87 tests in the Slack dispatch preview/streaming shard; format, lint, and diff check passed; autoreview returned clean after one accepted finding was fixed. PR body includes live before/after Slack screenshots from the contributor's production workspace.

Observed result after fix: status_final skips only the draft message-id reset, keeps boundary cleanup, preserves last non-empty progress lines for rich and text renderers, and keeps partial/replace forceNewMessage behavior covered by regression test.

What was not tested: I did not run a new live Slack send from this maintainer checkout.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
Keep Slack progress-mode drafts on one rolling preview message across assistant and reasoning boundaries while preserving boundary cleanup and the latest visible tool-progress lines. Partial/replace modes still start a fresh draft at assistant boundaries.

Co-authored-by: Mike Harrison <[email protected]>
@steipete
steipete force-pushed the fix/slack-progress-single-draft branch from 947a719 to 8286d36 Compare May 31, 2026 16:04
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@steipete

Copy link
Copy Markdown
Contributor

Refreshed maintainer proof on exact head 8286d36:

Behavior addressed: Slack progress-mode drafts stay on one rolling preview message across assistant/reasoning boundaries, while partial/replace modes still force a new draft at assistant boundaries.

Real environment tested: contributor's production Slack proof remains in the PR body; maintainer local proof covered the Slack dispatch boundary behavior on the rebased head.

Exact steps or command run after this patch:

  • node scripts/run-vitest.mjs extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts extensions/slack/src/monitor/message-handler/dispatch.streaming.test.ts --reporter=dot
  • ./node_modules/.bin/oxfmt --check extensions/slack/src/monitor/message-handler/dispatch.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts
  • ./node_modules/.bin/oxlint --tsconfig ./tsconfig.json extensions/slack/src/monitor/message-handler/dispatch.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts
  • ./node_modules/.bin/oxlint --tsconfig config/tsconfig/oxlint.core.json src/gateway/gateway-acp-spawn-defaults.live.test.ts --type-aware --report-unused-disable-directives-severity error
  • git diff --check origin/main...HEAD
  • /Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode commit --commit HEAD

Evidence after fix: focused Vitest passed 87 tests; format, lint, diff check, and the moving-base gateway lint probe passed; autoreview returned clean after the accepted text-renderer progress finding was fixed.

Observed result after fix: status_final skips only the draft message-id reset, keeps boundary cleanup, preserves last non-empty progress lines for rich and text renderers, and keeps partial/replace forceNewMessage behavior covered by regression test.

What was not tested: I did not run a new live Slack send from this maintainer checkout.

@steipete
steipete merged commit 63d0c1d into openclaw:main May 31, 2026
132 of 141 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 1, 2026
Keep Slack progress-mode drafts on one rolling preview message across assistant and reasoning boundaries while preserving boundary cleanup and the latest visible tool-progress lines. Partial/replace modes still start a fresh draft at assistant boundaries.

Co-authored-by: Peter Steinberger <[email protected]>
SYU8384 pushed a commit to SYU8384/openclaw that referenced this pull request Jun 3, 2026
Keep Slack progress-mode drafts on one rolling preview message across assistant and reasoning boundaries while preserving boundary cleanup and the latest visible tool-progress lines. Partial/replace modes still start a fresh draft at assistant boundaries.

Co-authored-by: Peter Steinberger <[email protected]>
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
Keep Slack progress-mode drafts on one rolling preview message across assistant and reasoning boundaries while preserving boundary cleanup and the latest visible tool-progress lines. Partial/replace modes still start a fresh draft at assistant boundaries.

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

Labels

channel: slack Channel integration: slack merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants