Skip to content

fix(mattermost): keep message tool replies in threads#93424

Merged
vincentkoc merged 6 commits into
mainfrom
ak/mattermost-thread-root-fix
Jun 16, 2026
Merged

fix(mattermost): keep message tool replies in threads#93424
vincentkoc merged 6 commits into
mainfrom
ak/mattermost-thread-root-fix

Conversation

@amknight

@amknight amknight commented Jun 15, 2026

Copy link
Copy Markdown
Member

Summary

  • Keep Mattermost message-tool sends in the thread root when generic replyTo names a child post and threadId carries the root.
  • Normalize bare 26-character Mattermost channel IDs for auto-threading and same-target matching, including replyToMode: "first" consumption.
  • Canonicalize message-action reply/thread metadata for one-root transports before outbound session mirroring.

Verification

  • node scripts/run-vitest.mjs extensions/mattermost/src/channel.test.ts extensions/mattermost/src/session-route.test.ts
  • node scripts/run-vitest.mjs src/infra/outbound/message-action-runner.threading.test.ts
  • git diff --check -- extensions/mattermost/src/channel.ts extensions/mattermost/src/channel.test.ts extensions/mattermost/src/session-route.ts extensions/mattermost/src/session-route.test.ts src/infra/outbound/message-action-threading.ts src/infra/outbound/message-action-runner.threading.test.ts
  • .agents/skills/autoreview/scripts/autoreview --mode local
  • Testbox-through-Crabbox: tbx_01kv6n3vr04nnkjc1rs255kdhj, Actions run https://github.com/openclaw/openclaw/actions/runs/27579510410, ran node scripts/run-vitest.mjs extensions/mattermost/src/channel.test.ts extensions/mattermost/src/session-route.test.ts src/infra/outbound/message-action-runner.threading.test.ts with 75 tests passing.
  • Tested end to end against local Mattermost
image

@openclaw-barnacle openclaw-barnacle Bot added channel: mattermost Channel integration: mattermost size: S maintainer Maintainer-authored PR labels Jun 15, 2026
@amknight
amknight marked this pull request as ready for review June 15, 2026 22:43
@amknight

Copy link
Copy Markdown
Member Author

Adversarial self-review

Reviewed by reading the full changed files in context and tracing both the runner send path (executeSendActiontryHandleWithPluginActiondispatchChannelMessageActionhandleAction) and the canonicalization in resolveAndApplyOutboundThreadId, plus the Mattermost + Slack threading adapters and the existing tests. Did not run the suite locally (my checkout is behind origin/main); relied on static analysis + the green Testbox run cited above.

Verified understanding

Three coupled changes:

  1. extensions/mattermost/src/channel.ts:446-449replyToId ?? threadId ?? replyTo precedence flip. Reachable in production: MM supportsAction returns true for send and has no actions.prepareSendPayload, so sends route through handleAction.
  2. extensions/mattermost/src/channel.ts:277-296normalizeMattermostThreadTarget / matchesMattermostToolContextTarget. Genuine root cause: normalizeMattermostMessagingTarget returns undefined for bare names, so the target comparison in resolveMattermostAutoThreadId silently failed and auto-threading was skipped.
  3. src/infra/outbound/message-action-threading.ts:52-67 — canonicalization now runs whenever replyToId && resolvedThreadId, extending it to the explicit-threadId case (was auto-resolved-only).

Well-targeted fix, correct root cause, comments updated, backward-compat for non-opt-in transports still covered by the existing "uses explicit forum threadId without rewriting replyTo" test.

Findings

1. [Medium] The shared message-action-threading.ts change alters Slack, but only Mattermost was verified.
Slack is the other provider implementing resolveReplyTransport (extensions/slack/src/channel.ts:817). The new case-3 path is reachable for Slack (explicit threadId + auto-populated replyTo): it now canonicalizes replyTo to the explicit threadId instead of threading under the inbound message ts. I believe this is more correct (respects the agent's explicit threadId; Slack flattens threads), so no concrete regression — but it's a core/shared edit that changes Slack's outbound thread_ts while the PR is scoped/verified Mattermost-only, and no Slack test covers this path (action-threading.test.ts only covers resolveSlackAutoThreadId; the core canonicalization test only covers the unchanged auto-resolved case). Please add a Slack case-3 assertion or document the Slack reasoning + run Slack threading tests.

2. [Low-Medium] normalizeMattermostThreadTarget ignores 53-char DM channel IDs and is a third MM-id encoding.
channel.ts:283 matches only /^[a-z0-9]{26}$/i, but existing looksLikeMattermostTargetId recognizes both 26-char IDs and 53-char DM IDs (<26>__<26>). A bare 53-char DM channel id as to won't normalize, so auto-threading / same-target matching (and the replyToMode:"first" consumption riding on matchesToolContextTarget) misses for that shape. Consider reusing/extending looksLikeMattermostTargetId so the ID heuristic lives in one place, or comment why 26-char-only.

3. [Low] Canonicalization bypasses the MM DM (chatType:"direct") branch.
message-action-threading.ts:56-61 calls resolveReplyTransport without replyDelivery, so MM's chatType === "direct" branch (which returns replyToId: null, channel.ts:907-911) is skipped and a DM with a resolvable thread gets replyTo→root. Mirrors pre-existing auto-path behavior and MM DMs do support threads, so likely fine — worth confirming against the in-flight mattermost-dm-validation work.

4. [Nit] Redundant guard at message-action-threading.ts:64: replyToId && is already guaranteed truthy by the outer if (replyToId && resolvedThreadId) (line 55).

5. [Nit] /^[a-z0-9]{26}$/i could treat a 26-char all-alnum channel name as an ID; impact is negligible (only the threading comparison, not target resolution), but a one-line "deliberate heuristic" comment would help.

6. [Nit] PR body's git diff --check lists session-route.ts / session-route.test.ts, which aren't in this 4-file PR — tidy the body.

Bottom line

Correct root-cause fix with good Mattermost coverage. Main thing to address before merge is #1 — the core/shared edit changes Slack's threading; add a Slack assertion or document/verify that path. #2-#3 are edge-correctness follow-ups; #4-#6 are cleanup.

@vincentkoc vincentkoc self-assigned this Jun 15, 2026
@amknight
amknight force-pushed the ak/mattermost-thread-root-fix branch from 548030e to 7366592 Compare June 15, 2026 23:02
@vincentkoc
vincentkoc force-pushed the ak/mattermost-thread-root-fix branch from 7366592 to 28725ab Compare June 15, 2026 23:36
@openclaw-barnacle openclaw-barnacle Bot added size: M agents Agent runtime and tooling and removed size: S labels Jun 15, 2026
@amknight
amknight force-pushed the ak/mattermost-thread-root-fix branch from c209f40 to 532dbba Compare June 16, 2026 00:06
@vincentkoc
vincentkoc force-pushed the ak/mattermost-thread-root-fix branch from 532dbba to e75e1e6 Compare June 16, 2026 00:17
@openclaw-barnacle openclaw-barnacle Bot removed the agents Agent runtime and tooling label Jun 16, 2026
@vincentkoc

Copy link
Copy Markdown
Member

land-ready verification:

  • canonicalized generic Mattermost message-action replies to the resolved root so delivery and outbound session mirroring stay on the same thread; direct provider actions still preserve explicit reply-target precedence
  • dropped an accidental unrelated session-cache commit from the PR branch before this final head
  • node scripts/run-vitest.mjs src/infra/outbound/message-action-runner.core-send.test.ts src/infra/outbound/message-action-runner.threading.test.ts extensions/mattermost/src/channel.test.ts extensions/slack/src/channel.test.ts — 123 passed
  • node_modules/.bin/oxfmt --check ... and git diff --check — clean
  • fresh autoreview — clean, no accepted/actionable findings
  • all relevant CI checks are green; check-additional-runtime-topology-architecture is the shared current-main failure at src/agents/auth-profiles/sqlite.ts:103, outside this PR

This lands the scoped message-tool threading fix. #45082 remains open because its wider proactive-message behavior is only partially addressed here.

@vincentkoc
vincentkoc merged commit 2365a13 into main Jun 16, 2026
163 of 164 checks passed
@vincentkoc
vincentkoc deleted the ak/mattermost-thread-root-fix branch June 16, 2026 00:37
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 16, 2026
* fix(mattermost): keep message tool replies in threads

* fix(outbound): preserve one-root reply threading

* fix(outbound): preserve explicit reply target precedence

* fix(mattermost): mirror inherited replies to root session

* test(outbound): align reply transport contract

* fix(mattermost): align mirrored thread root

---------

Co-authored-by: Alex Knight <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
crh-code pushed a commit to crh-code/openclaw that referenced this pull request Jun 18, 2026
* fix(mattermost): keep message tool replies in threads

* fix(outbound): preserve one-root reply threading

* fix(outbound): preserve explicit reply target precedence

* fix(mattermost): mirror inherited replies to root session

* test(outbound): align reply transport contract

* fix(mattermost): align mirrored thread root

---------

Co-authored-by: Alex Knight <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
badgerbees pushed a commit to badgerbees/openclaw that referenced this pull request Jul 8, 2026
* fix(mattermost): keep message tool replies in threads

* fix(outbound): preserve one-root reply threading

* fix(outbound): preserve explicit reply target precedence

* fix(mattermost): mirror inherited replies to root session

* test(outbound): align reply transport contract

* fix(mattermost): align mirrored thread root

---------

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

Labels

channel: mattermost Channel integration: mattermost maintainer Maintainer-authored PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants