From fe8d0d5a9b8f7a8980947c36ab5e549ef78dc7da Mon Sep 17 00:00:00 2001 From: teconomix Date: Fri, 20 Mar 2026 16:39:27 +0000 Subject: [PATCH] fix(mattermost): normalize both sides before divergence check (ID=2965488514) [[reply_to_current]] sets payload.replyToId to the child-post id inside the thread, not the thread root. The raw !== comparison triggered false divergence: child-post != thread-root, even though they both resolve to the same Mattermost thread. Fix: compute baseReplyToId via resolveMattermostReplyRootId without the payload, then compare finalReplyToId against baseReplyToId. Both paths normalize child-post ids to the thread root before comparison, so [[reply_to_current]] and explicit child-post targets no longer falsely trigger the divergent-target path. --- .../mattermost/src/mattermost/monitor.ts | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/extensions/mattermost/src/mattermost/monitor.ts b/extensions/mattermost/src/mattermost/monitor.ts index a14d6d1ebba..853021b2c36 100644 --- a/extensions/mattermost/src/mattermost/monitor.ts +++ b/extensions/mattermost/src/mattermost/monitor.ts @@ -1549,21 +1549,26 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {} // Compute reply target divergence before flushing, so we don't // accidentally create a preview post in the wrong thread on flush. - // Compute the reply target for this payload. When payload.replyToId is set - // and resolves to a different thread than the one the streaming preview was - // created in (effectiveReplyToId), we must not patch the preview in-place. - // We compare the raw payload.replyToId against effectiveReplyToId directly - // instead of going through resolveMattermostReplyRootId(), because that - // helper always returns threadRootId when set, making the comparison always - // false when effectiveReplyToId is non-empty (ID=2965349638). + // Compute the reply target for this payload. When payload.replyToId resolves + // to a different Mattermost thread root than effectiveReplyToId, we must not + // patch the preview in-place (different thread). + // + // Both sides go through resolveMattermostReplyRootId so that child-post IDs + // (e.g. from [[reply_to_current]] inside a thread) are normalized to the same + // thread root as effectiveReplyToId before comparing. Raw payload.replyToId + // comparison was wrong: [[reply_to_current]] sets a child-post id that differs + // from the thread root but resolves to the same thread (ID=2965488514). const finalReplyToId = resolveMattermostReplyRootId({ threadRootId: effectiveReplyToId, replyToId: payload.replyToId, }); + const baseReplyToId = resolveMattermostReplyRootId({ + threadRootId: effectiveReplyToId, + }); const replyTargetDiverged = payload.replyToId != null && payload.replyToId.trim() !== "" && - payload.replyToId.trim() !== effectiveReplyToId; + finalReplyToId !== baseReplyToId; if (isFinal && blockStreamingClient) { if (replyTargetDiverged) {