Skip to content

fix(slack): preserve buffered thread stream replies#78536

Merged
steipete merged 13 commits into
mainfrom
fix/slack-thread-delivery-78061
Jun 19, 2026
Merged

fix(slack): preserve buffered thread stream replies#78536
steipete merged 13 commits into
mainfrom
fix/slack-thread-delivery-78061

Conversation

@vincentkoc

@vincentkoc vincentkoc commented May 6, 2026

Copy link
Copy Markdown
Member

Summary

  • Preserve locally buffered Slack thread reply tails when native stream finalization is definitively rejected before Slack receives them.
  • Route only those definite Slack API failures through the existing threaded reply path; ambiguous transport/server failures remain errors to avoid duplicate delivery.
  • Propagate failed fallback delivery while retaining thread participation after a visible partial stream.

Closes #78061. Related: #78059.

Root cause

Slack SDK ChatStreamer buffers short markdown_text locally. OpenClaw already recovered buffered text for a narrow set of finalization failures, but did not include method_not_supported_for_channel_type. The original PR idea broadened recovery to every finalization failure; review showed that would risk duplicate messages when a transport failure happened after Slack accepted the stop request.

This revision keeps the existing explicit, definitive-error allowlist. It also makes fallback failure observable instead of silently treating an earlier partial stream as overall success.

Verification

  • node scripts/run-vitest.mjs extensions/slack/src/streaming.test.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts — 2 files, 103 tests passed
  • node_modules/.bin/oxfmt --check extensions/slack/src/monitor/message-handler/dispatch.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts — passed
  • git diff --check — passed
  • Crabbox Azure pnpm check:changed — passed; run run_b851396c0d41, lease cbx_f5bb0fdc7b61 (stopped)
  • Fresh branch autoreview — no actionable findings; correctness confidence 0.94

Real behavior proof

  • Behavior addressed: Slack thread replies no longer lose a locally buffered tail when native stream finalization returns a definitive unsupported-channel rejection.
  • Real environment tested: OpenClaw Slack dispatch and SDK-boundary regression tests on macOS; changed type/lint/guard lanes on Linux via Azure Crabbox.
  • Exact steps or command run after this patch: node scripts/run-vitest.mjs extensions/slack/src/streaming.test.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts
  • Evidence after fix: 103 targeted tests passed; remote changed gate passed on run_b851396c0d41.
  • Observed result after fix: definite finalization rejection delivers only pending buffered text through the original Slack thread; ambiguous transport/internal failures do not retry; failed tail fallback rejects; visible partial delivery still records thread participation.
  • What was not tested: live Slack Socket Mode delivery. The regression is covered at the Slack SDK stream wrapper and message-dispatch seams without live credentials.

Compatibility and risk

  • No config, migration, permission, token, or public API changes.
  • No new network path; fallback uses existing Slack reply delivery.
  • Duplicate-delivery risk is bounded by retrying only explicit Slack API codes known to reject before buffered text reaches Slack.

@openclaw-barnacle openclaw-barnacle Bot added channel: slack Channel integration: slack size: S maintainer Maintainer-authored PR labels May 6, 2026
@clawsweeper

clawsweeper Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 19, 2026, 9:00 AM ET / 13:00 UTC.

Summary
The branch adds method_not_supported_for_channel_type to Slack native stream finalize fallback handling and routes buffered tails through existing threaded reply delivery with regression tests.

Reproducibility: yes. at source level: @slack/web-api ChatStreamer can keep short markdown locally until stop, and current main plus v2026.6.8 do not classify the unsupported-channel finalize code for fallback delivery. I did not establish live Slack workspace reproduction.

Review metrics: 2 noteworthy metrics.

  • Effective Merge Surface: 4 Slack files in potential merge commit 42d9d16. The stale PR base reports 271 files, but the current-main merge result keeps review focused on Slack streaming behavior.
  • Slack Finalize Fallback Codes: 1 added. The added Slack API code controls when locally buffered stream text is retried through normal threaded delivery.

Stored data model
Persistent data-model change detected: serialized state: src/plugins/runtime/runtime-web-channel-plugin.ts, unknown-data-model-change: src/plugins/openai-compatible-embedding-provider.test.ts, unknown-data-model-change: src/plugins/openai-compatible-embedding-provider.ts, unknown-truncated-pull-files, vector/embedding metadata: src/plugins/openai-compatible-embedding-provider.test.ts, vector/embedding metadata: src/plugins/openai-compatible-embedding-provider.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #78061
Summary: This PR is the candidate fix for the canonical Slack thread outbound reply-loss issue; the idle-reset report overlaps in user symptom but has a distinct session-state root cause.

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: 🦞 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.

Rank-up moves:

  • Wait for exact-head queued checks to finish.
  • [P2] Add live Slack proof if maintainers want transport-level confidence before merge.

Mantis proof suggestion
A real Slack proof would materially reduce the remaining uncertainty that the buffered tail lands once in the original thread. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis slack desktop smoke: verify that a native-stream Slack thread fallback delivers the buffered tail exactly once in the original thread.

Risk before merge

  • [P1] Maintainers need to accept that method_not_supported_for_channel_type is a definitive pre-delivery Slack native-stream rejection; a wrong classification could duplicate or drop buffered thread text.
  • [P1] No live Slack Socket Mode or Slack Desktop stream-interruption proof was inspected, so transport behavior is proven through Slack SDK source plus OpenClaw seam tests/Testbox rather than in a real workspace.
  • [P1] Exact-head GitHub CI/CodeQL for 0d8d75918d0bb47e0c2eccd2e49c2f6a427922a9 was still queued/unknown; prior hosted release-gate proof covers a3155ca99a8945150113f6b46a63feda3f752f07.

Maintainer options:

  1. Land After Accepting The Slack Error Classification (recommended)
    Maintainers can merge once exact-head validation passes if they agree this Slack code means native streaming was rejected before buffered text reached Slack.
  2. Require Live Slack Proof First
    Maintainers can ask for Slack Socket Mode or Slack Desktop proof that a buffered tail lands exactly once in the original thread before merge.
  3. Pause If Slack Semantics Stay Unclear
    If the error can occur after Slack accepts finalization, pause this branch and replace it with narrower detection or an opt-out from native streaming for unsupported channel types.

Next step before merge

  • [P2] This protected maintainer/member PR has no discrete automation repair; the remaining action is maintainer acceptance of Slack error semantics plus exact-head validation.

Security
Cleared: No concrete security or supply-chain regression was found in the effective Slack-only merge diff; it changes no dependencies, workflows, permissions, secrets, or token paths.

Review details

Best possible solution:

Land this four-file Slack-only merge result, or an equivalent patch, after maintainer acceptance of the definitive-error allowlist and exact-head validation.

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

Yes at source level: @slack/web-api ChatStreamer can keep short markdown locally until stop, and current main plus v2026.6.8 do not classify the unsupported-channel finalize code for fallback delivery. I did not establish live Slack workspace reproduction.

Is this the best way to solve the issue?

Yes: the PR extends the existing Slack-owned finalize fallback allowlist and reuses deliverReplies, which is narrower than changing routing, config, or streaming defaults. The remaining judgment is whether maintainers accept the Slack API semantics without live transport proof.

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🦞 diamond lobster.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.

Label justifications:

  • P1: The linked bug reports generated Slack thread replies being silently lost, breaking a real channel workflow.
  • merge-risk: 🚨 message-delivery: The PR changes when Slack stream finalization failures are retried, so an incorrect error classification could drop or duplicate reply text.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: The external-contributor proof gate does not apply to this member/maintainer PR; the body and maintainer comment provide targeted tests and Testbox proof, but no live Slack workspace proof.
Evidence reviewed

What I checked:

  • Repository policy read: Root AGENTS.md and the scoped extensions guide were read; protected maintainer handling, message-delivery compatibility risk, and dependency inspection guidance apply to this review. (AGENTS.md:30, ce7f89916522)
  • Effective merge surface: Comparing current main to GitHub's potential merge commit shows the actual merge candidate changes only four Slack streaming files; the broader 271-file PR listing is stale-base noise, not the effective merge diff. (42d9d16f1547)
  • Current main behavior: Current main's Slack finalize allowlist includes user_not_found, team_not_found, and missing_recipient_user_id, but not method_not_supported_for_channel_type. (extensions/slack/src/streaming.ts:322, ce7f89916522)
  • Latest release behavior: The latest release tag v2026.6.8 has the same Slack finalize allowlist gap, so the PR is not already shipped. (extensions/slack/src/streaming.ts:322, 844f405ac1be)
  • PR behavior: The PR head adds method_not_supported_for_channel_type as a definitive channel-type rejection and leaves ambiguous transport/server failures outside the allowlist. (extensions/slack/src/streaming.ts:323, 0d8d75918d0b)
  • Fallback owner boundary: The PR routes pending buffered stream text through deliverReplies with the original thread timestamp, preserving the existing Slack reply path instead of adding a parallel sender. (extensions/slack/src/monitor/message-handler/dispatch.ts:845, 0d8d75918d0b)

Likely related people:

  • mvanhorn: Merged PR fix(slack): treat Slack Connect finalize errors as benign in stopSlackStream #70370 introduced the Slack finalize-error fallback seam and SlackStreamNotDeliveredError behavior this PR extends. (role: introduced related fallback behavior; confidence: high; commits: 2e90a2247edd, e55b93263212; files: extensions/slack/src/streaming.ts, extensions/slack/src/streaming.test.ts, extensions/slack/src/monitor/message-handler/dispatch.ts)
  • martingarramon: Merged PR fix(slack): route stream-fallback delivery through chunked sender (follow-up to #70370) #71124 routed pending stream fallback through the chunked sender in the same Slack dispatch path. (role: adjacent fallback hardening contributor; confidence: high; commits: 150053bc8699; files: extensions/slack/src/monitor/message-handler/dispatch.ts, extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts)
  • steipete: Recent Slack streaming/progress commits and the latest branch commits refine fallback failure propagation and partial-stream participation; live PR state assigns this PR to steipete. (role: recent area contributor and assigned reviewer; confidence: high; commits: 7c4601ec73fc, 842e6f16437c, 0d8d75918d0b; files: extensions/slack/src/streaming.ts, extensions/slack/src/monitor/message-handler/dispatch.ts, extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts)
  • rishitamrakar: Recent current-main history on Slack streaming and dispatch surfaces includes message_sent hook work across streaming, fallback, and normal outbound reply paths. (role: recent adjacent Slack delivery contributor; confidence: medium; commits: dc493bc9a2b6; files: extensions/slack/src/streaming.ts, extensions/slack/src/monitor/message-handler/dispatch.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.

@byungskers byungskers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Excellent bug fix with thorough documentation and test coverage. The Slack native streaming buffer contract is tricky, and losing short replies because stopStream failed before flush is a frustrating user experience.

A few constructive notes:

  1. Fallback delivery duplication risk: The PR mentions that pendingText is cleared after acknowledged native flushes, which avoids replay. Could you add a test that explicitly verifies no duplicate delivery occurs if a partial flush succeeded before the final stop failure?

  2. Error classification: The change broadens the error allowlist for fallback delivery. Is there any error type where fallback delivery would be incorrect (e.g., rate limits or auth failures where retrying via chat.postMessage would also fail)? The current approach seems safe since it only posts already-generated text, but worth confirming.

  3. Testbox gap: You noted Testbox was unavailable for pnpm check:changed. If this merges before you can run it, consider scheduling a follow-up Testbox run or asking a maintainer to trigger one — the Slack extension has enough surface area that changed-surface validation is valuable.

The real behavior proof section is particularly well done. The before/after flow diagram makes the change easy to understand. LGTM with minor test suggestions.

@sean-codevasp

Copy link
Copy Markdown

when will this be merged to main?

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jun 14, 2026
@steipete steipete self-assigned this Jun 19, 2026
@steipete
steipete force-pushed the fix/slack-thread-delivery-78061 branch from 552ebcc to 1799121 Compare June 19, 2026 07:43
@steipete
steipete marked this pull request as ready for review June 19, 2026 07:44
@blacksmith-sh

This comment has been minimized.

@steipete
steipete requested a review from a team as a code owner June 19, 2026 11:11
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: discord Channel integration: discord channel: imessage Channel integration: imessage channel: matrix Channel integration: matrix channel: msteams Channel integration: msteams labels Jun 19, 2026
@openclaw-barnacle openclaw-barnacle Bot added the channel: sms Channel integration: sms label Jun 19, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 19, 2026
@openclaw-barnacle openclaw-barnacle Bot added the channel: mattermost Channel integration: mattermost label Jun 19, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b3bec1a3b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +61 to +62
if let appGroupStateDirURL {
return appGroupStateDirURL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Badge Migrate existing identity before switching stores

When an installed iOS app is upgraded with the new App Group entitlement, this branch selects the empty App Group container before the old Application Support/OpenClaw directory. Previous builds wrote identity/device.json and identity/device-auth.json only under the legacy directory, so DeviceIdentityStore.loadOrCreate() will generate a new device id and DeviceAuthStore.loadToken() will miss saved gateway tokens, breaking trusted device auth and forcing users to re-pair. Please read/copy the legacy identity and auth files before preferring the App Group store.

Useful? React with 👍 / 👎.

@steipete

steipete commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Land-ready verification for 0d8d75918d0bb47e0c2eccd2e49c2f6a427922a9:

  • Finalizes buffered Slack native streams with an ordinary reply when the final stream update is unavailable, avoids duplicates, and preserves ambiguous errors.
  • Focused local proof: 103 Slack tests passed.
  • Exact flaky-shard proof: 411 tests passed in Testbox run run_d099d9d88862.
  • Changed-surface Testbox proof: run_b851396c0d41 passed.
  • Fresh autoreview: no actionable findings.
  • Exact-head hosted CI release gate after final mainline synchronization: 27826689440 passed.
  • Repository-native scripts/pr prepare-run 78536 passed.

Known gap: no live Slack workspace stream interruption; Slack API outcomes are covered through the native-stream test seam.

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jun 19, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a3155ca99a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


public enum ShareGatewayRelaySettings {
private static let suiteName = "group.ai.openclaw.shared"
private static var suiteName: String { OpenClawAppGroup.identifier }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Migrate share settings from the old app group

For users upgrading from builds that saved share relay or default-instruction state under the previous group.ai.openclaw.shared suite, this now reads only OpenClawAppGroup.identifier. That leaves ShareGatewayRelaySettings.loadConfig() empty until the main app reconnects, so the share extension can report that OpenClaw is not connected, and ShareToAgentSettings.loadDefaultInstruction() similarly drops the user's saved default share instruction. Please read/copy the old suite keys once before switching fully to the new app group.

Useful? React with 👍 / 👎.

@openclaw-barnacle openclaw-barnacle Bot added extensions: xai channel: zaloclawbot Channel integration: zaloclawbot labels Jun 19, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jun 19, 2026
@steipete
steipete merged commit cd2d837 into main Jun 19, 2026
180 of 185 checks passed
@steipete
steipete deleted the fix/slack-thread-delivery-78061 branch June 19, 2026 13:02
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

Thanks @vincentkoc!

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

Labels

agents Agent runtime and tooling app: ios App: ios channel: discord Channel integration: discord channel: imessage Channel integration: imessage channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: signal Channel integration: signal channel: slack Channel integration: slack channel: sms Channel integration: sms channel: telegram Channel integration: telegram channel: voice-call Channel integration: voice-call channel: whatsapp-web Channel integration: whatsapp-web channel: zaloclawbot Channel integration: zaloclawbot cli CLI command changes commands Command implementations docs Improvements or additions to documentation extensions: acpx extensions: github-copilot extensions: memory-core Extension: memory-core extensions: openai extensions: qa-lab extensions: xai gateway Gateway runtime maintainer Maintainer-authored PR merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P1 High-priority user-facing bug, regression, or broken workflow. plugin: google-meet rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. scripts Repository scripts size: XL 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.

Slack thread session generates responses but fails to deliver to Slack

4 participants