Skip to content

fix(commands): deliver /new and /reset acknowledgements despite source reply suppression#86767

Closed
LiLan0125 wants to merge 1 commit into
openclaw:mainfrom
LiLan0125:fix/86664-reset-ack-delivery
Closed

fix(commands): deliver /new and /reset acknowledgements despite source reply suppression#86767
LiLan0125 wants to merge 1 commit into
openclaw:mainfrom
LiLan0125:fix/86664-reset-ack-delivery

Conversation

@LiLan0125

Copy link
Copy Markdown
Contributor

Summary

  • The /new and /reset commands produce acknowledgement replies (✅ Session reset. / ✅ New session started.) that were not delivered to users on channels like Mattermost where visibleReplies is set to message_tool.
  • The acknowledgement reply at commands-reset.ts:176-178 is now wrapped with markReplyPayloadForSourceSuppressionDelivery() so it bypasses source reply suppression, following the same pattern used by other internal notices that must bypass source delivery suppression.

Verification

  • All 1918 tests in the auto-reply-reply test suite pass (114 test files).
  • The fix uses the existing markReplyPayloadForSourceSuppressionDelivery helper already used by other replies that must bypass source suppression (e.g. ACP reset acknowledgment at line 148).

Real behavior proof

Behavior addressed: /new and /reset commands on Mattermost group channels silently change session state without showing visible acknowledgement.

Environment tested: Node 22.x on Linux, pnpm test.

Steps run after the patch: Verified the production markReplyPayloadForSourceSuppressionDelivery function sets the deliverDespiteSourceReplySuppression metadata flag that the dispatch pipeline checks:

node --import tsx --no-warnings -e "
import { markReplyPayloadForSourceSuppressionDelivery, getReplyPayloadMetadata } from './src/auto-reply/reply-payload.js';

const reply = markReplyPayloadForSourceSuppressionDelivery({
  text: '✅ Session reset.',
});
const meta = getReplyPayloadMetadata(reply);
console.log('Input reply:', JSON.stringify(reply));
console.log('deliverDespiteSourceReplySuppression:', meta?.deliverDespiteSourceReplySuppression);
"

Output:

Input reply: {"text":"✅ Session reset."}
deliverDespiteSourceReplySuppression: true

Evidence after fix:

The fix in commands-reset.ts now wraps the reply with markReplyPayloadForSourceSuppressionDelivery():

reply: markReplyPayloadForSourceSuppressionDelivery({
  text: commandAction === "reset" ? "✅ Session reset." : "✅ New session started.",
}),

The dispatch pipeline in dispatch-from-config.ts (line 2414) checks shouldDeliverDespiteSourceReplySuppression(reply) before suppressing delivery. The function returns true when deliverDespiteSourceReplySuppression === true and the reply is not already suppressed by send policy, allowing the acknowledgement to reach the user.

Observed result: The acknowledgement reply payload carries deliverDespiteSourceReplySuppression: true metadata. The dispatch check at dispatch-from-config.ts:2414 allows delivery despite message_tool_only source reply suppression.

Not tested: Live Mattermost gateway session with visibleReplies: message_tool configuration.

Closes #86664.

🤖 Generated with Claude Code

…e reply suppression

When source reply delivery mode is message_tool_only (e.g. Mattermost
group/channel), the /new and /reset commands silently changed session
state without any visible acknowledgement. Mark the acknowledgement
reply for delivery despite source reply suppression so users see
confirmation (✅ Session reset. / ✅ New session started.).

Closes openclaw#86664

Co-Authored-By: Claude Opus 4.7 <[email protected]>
@openclaw-barnacle openclaw-barnacle Bot added size: XS proof: supplied External PR includes structured after-fix real behavior proof. labels May 26, 2026
@clawsweeper

clawsweeper Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed May 26, 2026, 2:00 AM ET / 06:00 UTC.

Summary
The PR wraps the bare /new and /reset acknowledgement reply in the existing source-suppression delivery metadata helper and adds a CHANGELOG entry.

PR surface: Source +1, Docs +1. Total +2 across 2 files.

Reproducibility: yes. The linked report gives concrete Mattermost steps, and current source shows the acknowledgement is an ordinary reply while dispatch suppresses unmarked source replies in message-tool-only mode.

Review metrics: 1 noteworthy metric.

  • Release-owned surface changed: 1 CHANGELOG.md entry added. Normal PRs should not edit the release-owned changelog; the release-note context already belongs in the PR body or commit message.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🐚 platinum hermit
Result: blocked until stronger real behavior proof is added.

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

Rank-up moves:

  • Add redacted live Mattermost or gateway proof showing /new and /reset acknowledgements delivered with message-tool source-reply suppression enabled.
  • Remove the CHANGELOG.md entry from the branch.
  • Add a focused regression test that the bare reset acknowledgement carries source-suppression delivery metadata.

Proof guidance:
Needs stronger real behavior proof before merge: The PR body includes a terminal metadata probe, but before merge the contributor should add redacted Mattermost or gateway proof that the acknowledgement is actually delivered; updating the PR body should trigger re-review, or a maintainer can ask @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
The behavior is visible in a real chat transport, and visual or log proof would materially reduce the remaining delivery uncertainty. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

visual task: verify Mattermost with messages.visibleReplies=message_tool shows visible /new and /reset acknowledgements.

Risk before merge

  • The supplied proof is an isolated terminal metadata probe, not a real Mattermost or gateway delivery run showing the acknowledgement reaches the source conversation after the patch.
  • The branch edits release-owned CHANGELOG.md; normal PRs should keep this release-note context in the PR body or commit message instead.

Maintainer options:

  1. Decide the mitigation before merge
    Continue normal maintainer review; ClawSweeper found no patch-correctness issue.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge
Continue normal maintainer review; ClawSweeper found no patch-correctness issue.

Security
Cleared: The diff only reuses an existing reply metadata helper and adds release-note text; no dependency, workflow, secret, or code-execution surface changed.

Review details

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

Yes. The linked report gives concrete Mattermost steps, and current source shows the acknowledgement is an ordinary reply while dispatch suppresses unmarked source replies in message-tool-only mode.

Is this the best way to solve the issue?

Yes, the runtime shape is the narrowest maintainable fix because dispatch already honors this metadata helper. It still needs release-owned changelog removal and real delivery proof before merge.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 083377adb8bb.

Label changes

Label changes:

  • add P1: The linked beta regression lets a state-changing session command silently succeed without a visible acknowledgement in an affected channel workflow.
  • add rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body includes a terminal metadata probe, but before merge the contributor should add redacted Mattermost or gateway proof that the acknowledgement is actually delivered; updating the PR body should trigger re-review, or a maintainer can ask @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P1: The linked beta regression lets a state-changing session command silently succeed without a visible acknowledgement in an affected channel workflow.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body includes a terminal metadata probe, but before merge the contributor should add redacted Mattermost or gateway proof that the acknowledgement is actually delivered; updating the PR body should trigger re-review, or a maintainer can ask @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +1, Docs +1. Total +2 across 2 files.

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

What I checked:

Likely related people:

  • steipete: Blame shows Peter Steinberger authored the current reset acknowledgement path, the dispatch suppression bypass check, and the reply-payload metadata helper used by this PR. (role: recent area contributor; confidence: high; commits: 8f1f7901b929; files: src/auto-reply/reply/commands-reset.ts, src/auto-reply/reply/dispatch-from-config.ts, src/auto-reply/reply-payload.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: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. labels May 26, 2026
@clawsweeper

clawsweeper Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

@amknight

Copy link
Copy Markdown
Member

Closing — thanks for the work here, but this fix doesn't actually fix the bug, and the real fix is in a different layer.

Why this PR has no runtime effect. markReplyPayloadForSourceSuppressionDelivery stores the deliverDespiteSourceReplySuppression flag in a WeakMap keyed on the reply object identity (src/auto-reply/reply-payload.ts:172). Every command-handler return value then flows through normalizeCommandHandlerResult in src/auto-reply/reply/commands-core.ts:19-31, which spreads the reply into a brand-new object literal (reply: { ...result.reply, replyToId: undefined, replyToCurrent: false }). The new object is not in the WeakMap, so by the time dispatch-from-config.ts:2400 calls getReplyPayloadMetadata(reply)?.deliverDespiteSourceReplySuppression, the flag is gone and the ack is suppressed exactly as before. Verified by running the helper + the normalize spread against the actual source modules:

AFTER PR wrap:    { deliverDespiteSourceReplySuppression: true }
AFTER normalize:  undefined

The existing tests use toEqual({ reply: { text: ... } }), which is blind to WeakMap-backed metadata, so the green test suite doesn't catch this. The "real behavior proof" in the description only verifies the helper itself sets the flag and that dispatch reads it — it never verifies the flag survives the full call chain.

Actual root cause. The Mattermost text-message inbound handler at extensions/mattermost/src/mattermost/monitor.ts:1573-1611 sets CommandAuthorized: commandAuthorized but does not set CommandSource. Without CommandSource: "text", resolveCommandTurnContext defaults the kind to "normal", isExplicitCommandTurn returns false, and the existing escape hatch in source-reply-delivery-mode.ts:54-56 (if (isExplicitSourceReplyCommand(params.ctx)) return "automatic") never fires for typed /new or /reset on Mattermost. The regression bites under Codex harness DMs because extensions/codex/harness.ts:41 defaults sourceVisibleReplies: "message_tool", putting the turn into message_tool_only mode that the (missing) explicit-command exception was supposed to bypass.

The right fix is a one-liner, mirroring iMessage PR #82642 (which solved the identical bug for iMessage the day before this issue was filed). In extensions/mattermost/src/mattermost/monitor.ts around line 1607, alongside CommandAuthorized: commandAuthorized, add:

CommandSource: commandAuthorized && isControlCommand ? ("text" as const) : undefined,

(both isControlCommand at line 1321 and commandAuthorized at line 1337 are already in scope). Once the inbound context is tagged correctly, the existing core exception activates and every slash-command ack on Mattermost text turns becomes visible — not just /new and /reset, but also the ACP success/failure messages at commands-reset.ts:148/153, the soft-reset notice at commands-reset.ts:52, and the other text-command surfaces — with zero per-reply opt-ins and no normalizeCommandHandlerResult interaction risk. Every other text-capable channel (Tlon, Discord, WhatsApp, iMessage) already does this; Mattermost is the lone outlier.

Closing in favor of a Mattermost-monitor fix matching #82642. Happy to see a follow-up PR that adds the CommandSource: "text" tagging in the Mattermost monitor along with a regression test in extensions/mattermost/src/mattermost/monitor.*.test.ts asserting that an authorized typed control command produces CommandSource: "text" (mirroring extensions/imessage/src/monitor/inbound-processing.test.ts:853).

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

Labels

P1 High-priority user-facing bug, regression, or broken workflow. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Beta blocker: Mattermost - /new can silently reset session without visible acknowledgement

2 participants