Skip to content

fix(slack): require delivery receipts for replies#80749

Open
sahilsatralkar wants to merge 1 commit into
openclaw:mainfrom
sahilsatralkar:issue-80715-slack-delivery-observability
Open

fix(slack): require delivery receipts for replies#80749
sahilsatralkar wants to merge 1 commit into
openclaw:mainfrom
sahilsatralkar:issue-80715-slack-delivery-observability

Conversation

@sahilsatralkar

Copy link
Copy Markdown
Contributor

Summary

  • Problem: Slack replies could be composed in the transcript while the delivery path treated ambiguous or
    unobservable sends as successful.
  • Why it matters: operators had no reliable Slack ts correlation or failure signal when normal inbound
    replies failed to appear in Slack.
  • What changed: Slack chat.postMessage replies now require a concrete timestamp, deliverReplies returns
    delivery identities, Slack dispatch marks delivery only after a real identity, and normal Slack replies emit
    message_sent correlation.
  • What did NOT change (scope boundary): no Slack delivery policy change, no auto-promotion of
    message_tool_only replies, no new Slack API fetch-back/reconciliation.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: Slack normal inbound replies are no longer marked delivered without a concrete
    Slack message identity; delivery correlation is emitted through message_sent.
  • Real environment tested: local OpenClaw checkout on macOS; no live Slack workspace credentials available
    locally.
  • Exact steps or command run after this patch: pnpm test ..., pnpm build, pnpm check:changed
  • Evidence after fix: targeted tests pass and changed gate passes; live Slack proof is blocked by missing local
    Slack credentials.
  • Observed result after fix: mocked Slack sends without ts now fail as ambiguous; successful sends propagate
    Slack timestamps into dispatch and hooks.
  • What was not tested: live Slack Socket Mode delivery against a real workspace.
  • Before evidence: issue report shows transcript-composed replies with no matching Slack
    conversations.replies / conversations.history messages.

Root Cause (if applicable)

  • Root cause: Slack chat.postMessage results without ts could fall through as "unknown", and
    deliverReplies returned void, so the dispatcher treated completed function calls as successful delivery
    without a concrete Slack receipt.
  • Missing detection / guardrail: normal Slack replies did not emit message_sent correlation, and
    message_tool_only final-text suppression had only verbose logging.
  • Contributing context (if known): rapid same-session replies and Slack thread replies made the lack of
    platform receipt/correlation hard to distinguish from successful transcript completion.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: extensions/slack/src/send.blocks.test.ts, extensions/slack/src/monitor/ replies.test.ts, extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts, src/infra/ outbound/deliver.test.ts, src/auto-reply/reply/dispatch-from-config.test.ts
  • Scenario the test should lock in: missing Slack ts rejects; delivered Slack IDs flow through reply delivery
    and message_sent; no-identity results do not mark delivery complete.
  • Why this is the smallest reliable guardrail: it exercises the Slack send, reply-delivery, dispatch, and hook
    seams without requiring live Slack credentials.
  • Existing test that already covers this (if any): Slack send queue serialization coverage existed, but not
    receipt validation/correlation.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

Slack delivery ambiguity now surfaces instead of being treated as success. Plugins observing message_sent can
now correlate normal Slack inbound replies with the delivered Slack timestamp.

Diagram (if applicable)

Before:
[assistant final] -> [deliverReplies returns] -> [marked delivered without Slack ts]

After:
[assistant final] -> [chat.postMessage ts required] -> [delivery identity returned] -> [message_sent
correlation]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: macOS local development checkout
  • Runtime/container: local Node/pnpm, no container
  • Model/provider: N/A for targeted regression tests
  • Integration/channel (if any): Slack
  • Relevant config (redacted): no live Slack credentials found locally

Steps

  1. Run targeted Slack/core regression tests.
  2. Run pnpm build.
  3. Run pnpm check:changed.

Expected

  • Slack sends without a chat.postMessage timestamp fail as ambiguous.
  • Successful Slack reply delivery returns real message identity and emits message_sent.

Actual

  • All targeted tests passed.
  • Build passed.
  • Changed gate passed.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: missing Slack ts, reply identity propagation, no-identity dispatch handling, message_sent
    correlation, message-tool-only suppression diagnostic, rapid same-session replies.
  • Edge cases checked: block sends, text sends, media-adjacent send path preservation, generic outbound session-
    key correlation.
  • What you did not verify: live Slack Socket Mode delivery, because no Slack keys were present in ~/.profile
    and no local Slack credential files were found.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: Slack API responses that previously produced "unknown" message IDs now fail as ambiguous.
    • Mitigation: Slack chat.postMessage should return ts for successful message posts; failing loudly is safer
      than marking an uncorrelated reply delivered.

Built with Codex

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

clawsweeper Bot commented May 11, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Summary
The PR requires Slack chat.postMessage timestamps before marking replies delivered, returns Slack delivery identities through normal reply dispatch, emits message_sent correlation, adds a message-tool-only suppression warning, and updates tests/changelog.

Reproducibility: no. full end-to-end current-main reproduction was established in this review. The failure is source-reproducible: current main can turn missing Slack ts into unknown, drops deliverReplies receipt data, and marks normal delivery after a void return while the linked issue supplies live Slack symptom evidence.

Real behavior proof
Needs real behavior proof before merge: Needs real behavior proof before merge: the PR body provides tests/build/check output but no live Slack proof, redacted runtime logs, terminal output, recording, or linked artifact showing the changed behavior after the fix; contributors should redact private details and update the PR body to trigger re-review.

Next step before merge
Contributor action is needed because this external PR only has mocked/test proof; ClawSweeper cannot supply the contributor’s live Slack evidence for them.

Security
Cleared: The diff changes Slack delivery control flow and tests without adding dependencies, permissions, secret handling, downloaded artifacts, or new code-execution surfaces.

Review details

Best possible solution:

Land a receipt-based Slack delivery fix after contributor-provided live or redacted runtime proof shows Slack timestamp correlation and no false delivered state; keep broader fallback/reconciliation policy in the related issues.

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

No full end-to-end current-main reproduction was established in this review. The failure is source-reproducible: current main can turn missing Slack ts into unknown, drops deliverReplies receipt data, and marks normal delivery after a void return while the linked issue supplies live Slack symptom evidence.

Is this the best way to solve the issue?

Yes, the PR direction is the narrow maintainable fix for this path: require concrete Slack timestamps and carry delivery identities into dispatch and hooks. The remaining blocker is real Slack proof, not a different implementation direction found in this pass.

What I checked:

  • Current main accepts ambiguous Slack send IDs: Current main still falls back to response.ts ?? "unknown" for block sends and lastMessageId || "unknown" for text sends, so a successful-looking Slack response without ts can become a delivered-looking result without a concrete Slack timestamp. (extensions/slack/src/send.ts:721, 0b5531749499)
  • Current main drops normal reply receipt data: deliverReplies awaits sendMessageSlack but returns no result, leaving Slack reply dispatch unable to require or expose the delivered Slack identity on this path. (extensions/slack/src/monitor/replies.ts:35, 0b5531749499)
  • Current main marks normal delivery after a void return: The normal Slack delivery closure awaits deliverReplies and then sets observedReplyDelivery = true; current main does not check for a concrete Slack receipt before marking the turn delivered. (extensions/slack/src/monitor/message-handler/dispatch.ts:660, 0b5531749499)
  • PR branch enforces timestamps and carries delivery identities: The PR adds requireSlackPostMessageTs, returns SlackReplyDeliveryResult[] from deliverReplies, checks delivery identity before marking normal delivery complete, and emits message_sent hooks with Slack correlation fields. (extensions/slack/src/send.ts:354, f35805d0c3dd)
  • PR branch adds focused regression coverage: The diff adds tests for missing Slack ts, delivery identity passthrough, no-identity dispatch handling, message_sent correlation, generic outbound session key correlation, and message-tool-only suppression diagnostics. (extensions/slack/src/send.blocks.test.ts:312, f35805d0c3dd)
  • Slack dependency contract supports requiring ts: Slack's OpenAPI schema for a successful chat.postMessage response requires ok, channel, ts, and message, so runtime validation of ts is consistent with the upstream contract.

Likely related people:

  • steipete: Recent GitHub path history shows repeated work on Slack send behavior, bundled plugin message lifecycle, and consolidated message delivery APIs adjacent to this receipt and hook path. (role: recent area contributor; confidence: high; commits: 22963259c9db, 05eda57b3c72, a4b17d65a8ff; files: extensions/slack/src/send.ts, extensions/slack/src/monitor/message-handler/dispatch.ts, extensions/slack/src/monitor/replies.ts)
  • vincentkoc: Recent commits touched Slack stream recipient caching, Slack message hot-path overhead, and outbound delivery lifecycle diagnostics close to the affected dispatch/correlation behavior. (role: adjacent Slack hot-path contributor; confidence: medium; commits: b09033e587c2, c0302512d4dd, bd32b1a906f3; files: extensions/slack/src/monitor/message-handler/dispatch.ts, extensions/slack/src/monitor/replies.ts, src/infra/outbound/deliver.ts)
  • bek91: Recent Slack thread participation work and the related open report on documented Slack message_sent correlation connect this person to the same delivery identity surface. (role: adjacent Slack thread/correlation contributor; confidence: medium; commits: cf3ce08b910e; files: extensions/slack/src/send.ts, extensions/slack/src/monitor/message-handler/dispatch.ts)

Remaining risk / open question:

  • No after-fix live Slack workspace proof, redacted runtime logs, terminal/live output, recording, or Slack API evidence is attached; the current proof is mocked tests and CI-style output only.
  • The PR does not add Slack fetch-back/reconciliation or auto-promotion fallback, so it may not fully close every broader transcript-composed/no-platform-message pattern in the linked open reports.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 0b5531749499.

Copy link
Copy Markdown

Live verification evidence from the PR checkout is now available.

Tested branch/commit:

  • Branch: issue-80715-slack-delivery-observability
  • Commit: f35805d0c3dd69e1bff20f228d7b9d676ebd1514
  • Runtime: macOS, Node 24.14.1
  • Active gateway process was confirmed listening on 127.0.0.1:18789 from the PR checkout.

Live Slack evidence:

  • A live Slack message-tool send was posted from the PR gateway into the originating Slack thread.
  • Slack returned a concrete delivery timestamp: 1778770801.620679
  • The sent message was read back from the same Slack thread.
  • The delivery receipt contained:
    • primaryPlatformMessageId=1778770801.620679
    • platformMessageIds=[1778770801.620679]
    • concrete channel/thread correlation
  • No unknown / ambiguous delivery identity was returned for this live send.

Important caveat:

  • The Slack session used for this verification had sourceReplyDeliveryMode: message_tool_only, so normal final-answer delivery was intentionally suppressed by session configuration.
  • This verifies the live PR gateway's Slack message-tool receipt path and confirms that real Slack timestamps are propagated instead of ambiguous unknown identities. It does not claim proof for normal final-answer delivery in a non-suppressed session.

@clawsweeper could you please re-review with this live evidence? We would really like to get this Slack delivery receipt fix merged.

@Jackten

Jackten commented May 15, 2026

Copy link
Copy Markdown
Contributor

I added related production evidence to #80715 here:

#80715 (comment)

Flagging it here because it may matter for this PR’s acceptance criteria.

The current live verification comment is useful, but it explicitly covers the Slack message-tool receipt path with sourceReplyDeliveryMode: message_tool_only. The incident I added was the normal source-final path: assistant final existed in the session transcript, the run ended successfully, but no Slack reply appeared, with a service-manager SIGTERM/restart in the same few-second window.

I’m not claiming this PR is wrong; the receipt work still looks directionally right. The remaining gap is proof/coverage for unsuppressed normal final-answer delivery, especially where final generation completes before a durable Slack receipt exists. In that path, pendingFinalDelivery should not be cleared until there is either a platform delivery receipt or a durable failed-delivery record.

@tracycollins

Copy link
Copy Markdown

seeing this problem too

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

Labels

channel: slack Channel integration: slack size: L triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Slack replies silently dropped: composed in transcript, never posted to Slack

4 participants