Skip to content

fix(mattermost): return 'unknown' ChatType when channel type is not resolvable#57970

Open
dave wants to merge 7 commits intoopenclaw:mainfrom
dave:fix/mattermost-unknown-chat-type
Open

fix(mattermost): return 'unknown' ChatType when channel type is not resolvable#57970
dave wants to merge 7 commits intoopenclaw:mainfrom
dave:fix/mattermost-unknown-chat-type

Conversation

@dave
Copy link
Copy Markdown

@dave dave commented Mar 30, 2026

Summary

  • Problem: mapMattermostChannelTypeToChatType returned "channel" for null/undefined input, making a failed channel lookup indistinguishable from a successful public-channel lookup.
  • Why it matters: When a channel lookup fails (e.g. missing channel type in WebSocket event), posts were routed to the wrong agent session — appearing in the main channel instead of the correct thread or DM session.
  • What changed: mapMattermostChannelTypeToChatType(null/undefined) now returns "unknown". All dispatch paths (handlePost, dispatchButtonClick, handleReactionEvent, resolveSessionKey) early-exit on "unknown" with a verbose log drop instead of silently misrouting. "unknown" added to ChatType, MattermostChatTypeKey, and the ok: false branch of MattermostCommandAuthDecision. Type cascade fixes in SlashInvocationAuth, resolveSlackReplyToMode, and buildChannelOutboundSessionRoute.
  • What did NOT change: The fallback for non-null unrecognised type strings (e.g. "x") still returns "channel" — only the null/undefined case is affected.

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

Root Cause / Regression History (if applicable)

  • Root cause: mapMattermostChannelTypeToChatType had no guard for the null/undefined case — it fell through to return "channel", treating a missing channel type as a successful public-channel match.
  • Missing detection / guardrail: No test covered the null/undefined input path; the function's return type didn't include "unknown", so a wrong fallback was structurally invisible.
  • Prior context: The function was introduced alongside the Mattermost channel routing logic; the null case was never explicitly handled.
  • Why this regressed now: It was always wrong — first surfaced clearly when testing PR fix(mattermost): route thread replies correctly when replyToMode is off #57565, where bot replies were observed landing in the main channel instead of the originating thread.
  • If unknown, what was ruled out: N/A

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: monitor-gating.test.ts, monitor.channel-kind.test.ts
  • Scenario the test should lock in: mapMattermostChannelTypeToChatType(undefined) and mapMattermostChannelTypeToChatType(null) return "unknown", not "channel".
  • Why this is the smallest reliable guardrail: The mapping function is pure and deterministic — a direct unit test on the null/undefined inputs is the minimal reliable check.
  • Existing test that already covers this: None (tests previously asserted "channel" for undefined).
  • If no new test is added, why not: N/A — new assertions added to both test files.

User-visible / Behavior Changes

When a Mattermost channel lookup fails (channel type missing from event), the post/reaction/button click is now silently dropped (with a verbose log) instead of being misrouted to the wrong agent session. In practice this affects only broken/degenerated WebSocket events — normal Mattermost events always include a channel type.

Diagram (if applicable)

Before:
mapMattermostChannelTypeToChatType(null) -> "channel" -> routes to wrong session

After:
mapMattermostChannelTypeToChatType(null) -> "unknown" -> handlePost early-exits, post dropped

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS 15.3
  • Runtime/container: Node 22, OpenClaw 2026.3.28
  • Model/provider: N/A (routing layer, no model involved)
  • Integration/channel: Mattermost
  • Relevant config (redacted): Standard Mattermost account config

Steps

  1. Start gateway with Mattermost account configured
  2. Send a message in a channel where the WebSocket event is missing channel_type (or simulate by patching resolveChannelInfo to return null)
  3. Observe that with the fix, the post is dropped with a verbose log; without the fix it misroutes to the main channel session

Expected

  • Post silently dropped, mattermost: drop post (cannot determine channel type ...) logged at verbose level

Actual (before fix)

  • Post treated as a public channel message, routed to main channel session

Evidence

  • Failing test/log before + passing after (unit tests updated: mapMattermostChannelTypeToChatType(undefined) expectation changed from "channel" to "unknown")
  • Synthetic test on 2026.3.28: confirmed agent replies landed in main channel instead of originating thread when channel type could not be resolved

Human Verification (required)

  • Verified scenarios: tsgo type check passes clean. Unit tests pass: monitor-gating.test.ts, monitor.channel-kind.test.ts, monitor-auth.test.ts. Pre-commit checks (pnpm check) pass.
  • Edge cases checked: Unrecognised non-null strings (e.g. "x") still return "channel" — only null/undefined is affected.
  • What you did not verify: Live Mattermost integration test with a real server producing a null channel type event.

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.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: Posts that previously misrouted to the main channel session will now be silently dropped.
    • Mitigation: This only affects events where the channel type is genuinely missing — which represents broken/degenerated events that were already producing wrong behavior. Dropping is strictly better than misrouting.

@openclaw-barnacle openclaw-barnacle Bot added channel: mattermost Channel integration: mattermost channel: slack Channel integration: slack size: S labels Mar 30, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 30, 2026

Greptile Summary

This PR correctly fixes the root cause of a misrouting bug: when mapMattermostChannelTypeToChatType receives a null/undefined channel type (i.e., the channel lookup failed), it now returns "unknown" instead of "channel", making a failed lookup distinguishable from a successful public-channel lookup. All downstream dispatch paths (handlePost, dispatchButtonClick, handleReactionEvent, resolveSessionKey) are updated to guard against "unknown" and early-exit or degrade gracefully, and the ChatType union, MattermostChatTypeKey, and related types are extended consistently.

Key changes:

  • mapMattermostChannelTypeToChatType(null | undefined)"unknown" (was "channel")
  • All Mattermost dispatch paths drop or short-circuit on kind === "unknown" with verbose logging
  • SlashInvocationAuth refactored to a discriminated union so callers can type-narrow after an ok check
  • resolveSlackReplyToMode guarded against indexing replyToModeByChatType with "unknown"
  • buildChannelOutboundSessionRoute peer parameter widened to RoutePeer

One inconsistency found: In slash-http.ts, the authorizeSlashInvocation function still returns kind: "channel" / chatType: "channel" when the channel lookup fails (line 135–136), even though the SlashInvocationAuth ok: false branch was widened to permit "unknown". There is no runtime impact — the caller exits before consuming those fields when ok === false — but it leaves type and implementation out of sync.

Confidence Score: 5/5

  • Safe to merge — the fix is correct and complete across all main dispatch paths; the one inconsistency in slash-http.ts has no runtime impact.
  • All P0/P1 concerns are addressed. The only finding is a P2 style inconsistency in slash-http.ts where the implementation returns "channel" instead of "unknown" in an ok: false branch that is never consumed by the caller. The core fix and all guard paths are sound.
  • extensions/mattermost/src/mattermost/slash-http.ts lines 135–136 — implementation value ("channel") doesn't match the newly widened type ("unknown" allowed); no functional impact but worth aligning for consistency.

Comments Outside Diff (1)

  1. extensions/mattermost/src/mattermost/slash-http.ts, line 135-136 (link)

    P2 kind/chatType not updated to "unknown" in channel-lookup-failure branch

    The PR widened the ok: false branch of SlashInvocationAuth to include "unknown" for kind/chatType, but the implementation inside authorizeSlashInvocation still returns "channel" when channelInfo is null. This leaves the type and the implementation inconsistent.

    In practice this doesn't affect routing because the caller at line 289 (if (!auth.ok) { sendJsonResponse(...); return; }) exits before consuming kind/chatType — but it undermines the intent of the discriminated union refactor and could mislead a future caller that reads those fields from the ok: false result.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: extensions/mattermost/src/mattermost/slash-http.ts
    Line: 135-136
    
    Comment:
    **`kind`/`chatType` not updated to `"unknown"` in channel-lookup-failure branch**
    
    The PR widened the `ok: false` branch of `SlashInvocationAuth` to include `"unknown"` for `kind`/`chatType`, but the implementation inside `authorizeSlashInvocation` still returns `"channel"` when `channelInfo` is null. This leaves the type and the implementation inconsistent.
    
    In practice this doesn't affect routing because the caller at line 289 (`if (!auth.ok) { sendJsonResponse(...); return; }`) exits before consuming `kind`/`chatType` — but it undermines the intent of the discriminated union refactor and could mislead a future caller that reads those fields from the `ok: false` result.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/mattermost/src/mattermost/slash-http.ts
Line: 135-136

Comment:
**`kind`/`chatType` not updated to `"unknown"` in channel-lookup-failure branch**

The PR widened the `ok: false` branch of `SlashInvocationAuth` to include `"unknown"` for `kind`/`chatType`, but the implementation inside `authorizeSlashInvocation` still returns `"channel"` when `channelInfo` is null. This leaves the type and the implementation inconsistent.

In practice this doesn't affect routing because the caller at line 289 (`if (!auth.ok) { sendJsonResponse(...); return; }`) exits before consuming `kind`/`chatType` — but it undermines the intent of the discriminated union refactor and could mislead a future caller that reads those fields from the `ok: false` result.

```suggestion
      kind: "unknown",
      chatType: "unknown",
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix: return 'unknown' ChatType when Matt..." | Re-trigger Greptile

@byungsker

This comment was marked as spam.

Copy link
Copy Markdown

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

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: 41bb3489fb

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread extensions/mattermost/src/mattermost/monitor.ts Outdated
@dave dave force-pushed the fix/mattermost-unknown-chat-type branch from 8d10072 to 1b5302e Compare March 30, 2026 22:44
@dave
Copy link
Copy Markdown
Author

dave commented Mar 31, 2026

All bot review comments addressed:

  • Greptile P2 (slash-http kind/chatType inconsistency): fixed in 86785cb
  • Codex P1 (resolveSessionKey wrong-session contamination): fixed in 8d10072 — the throw is now before resolveAgentRoute so no route is computed or session key returned for unknown kinds
  • Contributor suggestion (comment on early-return): added clarifying comment, then superseded by the throw refactor

CI and pnpm check pass locally. Ready for review.

cc @mukhtharcm — this is a prerequisite for #57565 (thread-id fix with replyTo off).

dave and others added 5 commits April 1, 2026 09:01
…solvable

Previously, mapMattermostChannelTypeToChatType returned "channel" for
null/undefined input, masking failed channel lookups as valid routing state.
All dispatch paths (handlePost, dispatchButtonClick, handleReactionEvent,
resolveSessionKey) now early-exit on "unknown" instead of silently routing
to the wrong session. monitor-auth's unknown-channel deny path now correctly
sets kind/chatType to "unknown". SlashInvocationAuth updated to discriminated
union; resolveSlackReplyToMode guards against "unknown" indexing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…anch

Addresses Greptile review comment: the local channel-lookup-failure path in
authorizeSlashInvocation was still returning kind: "channel", inconsistent
with the discriminated union refactor and monitor-auth's unknown-channel deny.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Addresses contributor review suggestion: add a comment explaining why we
return the base session key early when kind is 'unknown', and why this is
safe (handlePost drops the post before the session key is used for routing).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eturning coerced key

Addresses Codex P1 review: returning a coerced 'channel' session key caused
the system event to be enqueued into the wrong session before dispatchButtonClick's
guard ever ran. Throwing instead causes the caller's try/catch in interactions.ts
to skip enqueueSystemEvent entirely, truly failing closed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…onKey

The throw for unknown kind was placed after resolveAgentRoute, doing
unnecessary work. Move it earlier to also eliminate the kind coercion
in the peer object.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dave dave force-pushed the fix/mattermost-unknown-chat-type branch from 1b5302e to 49c8e18 Compare March 31, 2026 22:01
Copy link
Copy Markdown

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

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: 49c8e1805b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +1048 to +1052
if (kind === "unknown") {
logVerboseMessage(
`mattermost: drop post (cannot determine channel type for ${channelId}, post=${post.id ?? "?"})`,
);
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid deduping posts before unknown-channel drop

This new kind === "unknown" early return drops the post after recentInboundMessages.check(...) has already marked its message ID as seen, so transient channel-type resolution failures can now cause avoidable message loss. If Mattermost resends/replays the same post ID after channel lookup recovers, the retry is treated as a duplicate and skipped for the full dedupe TTL instead of being processed.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 0eb76ff. Moved the unknown-channel guard to run before recentInboundMessages.check(), using payload.data?.channel_type which is available immediately without any async lookup. This way a transient unknown-channel post is dropped before its ID is registered in the dedup tracker.

…tracker

Addresses Codex review: the kind === "unknown" guard was placed after
recentInboundMessages.check(), so a transient unknown-channel post would
mark its ID as seen before being dropped. If Mattermost replayed the same
post after channel recovery, it would be incorrectly deduped. Move the
check before the dedup registration, using payload.data.channel_type which
is available immediately without a channelInfo lookup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

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

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: 0eb76ff8d6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +1023 to +1025
const channelTypeFromEvent = payload.data?.channel_type;
if (mapMattermostChannelTypeToChatType(channelTypeFromEvent) === "unknown") {
logVerboseMessage(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Defer unknown-channel drop until fallback lookup runs

handlePost now returns early when payload.data?.channel_type maps to "unknown", but channel_type is optional on MattermostEventPayload and this return happens before resolveChannelInfo(channelId) is consulted. In the channel_type-missing case, we drop the message immediately even when the channel API lookup could still provide a valid type, so inbound posts are lost unnecessarily. This guard should use the existing channelTypeFromEvent ?? channelInfo?.type fallback path before deciding to drop.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 3779f15. The early guard now calls resolveChannelInfo when channelTypeFromEvent maps to unknown — if the API returns a valid type we continue normally, only dropping when both the event field AND the API fallback fail. The second resolveChannelInfo call in the normal path hits the cache (same tick) so no extra network request is made.

Codex review: dropping immediately when payload.data.channel_type is missing
lost messages that the API lookup could have recovered. Now the early guard
only drops when both the event field AND the resolveChannelInfo API fallback
return unknown. The second resolveChannelInfo call hits the cache (same tick)
so no extra network request is made.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

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

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: 3779f15360

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


const channelInfo = await resolveChannelInfo(channelId);
const channelType = payload.data?.channel_type ?? channelInfo?.type ?? undefined;
const channelType = channelTypeFromEvent ?? channelInfo?.type ?? undefined;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use fallback channel type when event type is blank

handlePost now does a fallback lookup when payload.data.channel_type maps to "unknown", but the later assignment still uses channelTypeFromEvent ?? channelInfo?.type. If Mattermost sends an empty string for channel_type, that expression keeps the empty string (because it is not null/undefined), so kind becomes "unknown" and the post is dropped even when resolveChannelInfo(channelId) returned a valid type. This creates avoidable message loss on malformed-but-recoverable events.

Useful? React with 👍 / 👎.

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 28, 2026

Codex review: found issues before merge.

What this changes:

The PR changes Mattermost nullish channel-type mapping to unknown, adds fail-closed guards in Mattermost post/button/reaction/session routing, updates Mattermost auth/types/tests, and widens related ChatType/routing-adjacent typing.

Maintainer follow-up before merge:

The branch has narrow repairable issues, but it is also stale against current Mattermost post handling and changes the public ChatType/RoutePeer SDK contract, so a maintainer should decide the contract/rebase direction before automation edits it.

Security review:

Security review cleared: The diff does not add dependencies, CI execution, package resolution changes, secrets handling, permissions, or new command/network execution surfaces; the blocking issues are functional routing and release-process concerns.

Review findings:

  • [P2] Use the fallback type after blank event channel_type — extensions/mattermost/src/mattermost/monitor.ts:1063
  • [P3] Add the required changelog entry — extensions/mattermost/src/mattermost/monitor-gating.ts:5
Review details

Best possible solution:

Rebase the PR onto current main, preserve current main's trusted API channel lookup, fail closed only when both event data and the API lookup cannot produce a trusted non-empty channel type, and either keep unknown Mattermost-local or intentionally update the public SDK contract with matching docs/API checks. Add the focused mapper/fallback tests plus the required changelog entry before merge.

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

Yes. Current main is reproducible with the pure mapper test that still expects undefined to map to channel, and the PR regression is reproducible statically with payload.data.channel_type = "" plus a valid resolveChannelInfo(channelId).type.

Is this the best way to solve the issue?

No, not as currently patched. The fail-closed direction is correct, but the PR should carry a trusted non-empty event-or-API channel type through handlePost and settle the public ChatType contract before merge.

Full review comments:

  • [P2] Use the fallback type after blank event channel_type — extensions/mattermost/src/mattermost/monitor.ts:1063
    When payload.data.channel_type is "", the fallback lookup above can prove channelInfoFallback.type is valid, but this line still keeps the empty event value because ?? only skips null/undefined. kind then becomes unknown and the post is dropped even though the API lookup recovered the type; carry a trimmed non-empty event type or the fallback type into the normal path.
    Confidence: 0.93
  • [P3] Add the required changelog entry — extensions/mattermost/src/mattermost/monitor-gating.ts:5
    This is a user-visible Mattermost routing fix, but the PR file list has no CHANGELOG.md update. Repo policy requires a changelog entry for user-facing fixes before landing.
    Confidence: 0.85

Overall correctness: patch is incorrect
Overall confidence: 0.9

Acceptance criteria:

  • pnpm test extensions/mattermost/src/mattermost/monitor-gating.test.ts extensions/mattermost/src/mattermost/monitor.channel-kind.test.ts
  • pnpm test extensions/mattermost/src/mattermost/monitor.test.ts
  • pnpm check:changed in Testbox before merge

What I checked:

Likely related people:

  • steipete: Current blame for the Mattermost gating split points to Peter Steinberger, and recent history shows repeated Mattermost runtime, slash-command hardening, and plugin SDK/channel seam refactors touching the affected paths. (role: recent maintainer and SDK/routing boundary owner; confidence: high; commits: 9300d48244ca, 9e1b524a0019, 2a65bfee966e; files: extensions/mattermost/src/mattermost/monitor-gating.ts, extensions/mattermost/src/mattermost/monitor.ts, extensions/mattermost/src/mattermost/slash-http.ts)
  • Vincent Koc: Recent history shows Vincent Koc on Mattermost replay/dedupe changes close to handlePost and on plugin SDK boundary/cycle work that overlaps the public type-surface concern. (role: recent Mattermost/replay and plugin SDK maintainer; confidence: medium; commits: a7ac3c666c4e, fad06f7c2126, d3fc6c0cc79f; files: extensions/mattermost/src/mattermost/monitor.ts, extensions/mattermost/src/mattermost/monitor.test.ts, src/plugin-sdk/core.ts)
  • mukhtharcm: History and the PR discussion connect Muhammed Mukhthar CM to Mattermost model picker/native command interaction surfaces that use the affected button/slash routing paths. (role: adjacent Mattermost interaction owner; confidence: medium; commits: 4f08dcccfd71, b1b41eb44323; files: extensions/mattermost/src/mattermost/monitor.ts, extensions/mattermost/src/mattermost/slash-http.ts, extensions/mattermost/src/mattermost/monitor-auth.ts)

Remaining risk / open question:

  • The PR head is stale against current main's replay-guarded Mattermost handlePost flow, so the final fix should be rebased before validation.
  • Widening public ChatType/RoutePeer to include unknown may affect plugin SDK and routing contracts; this needs an explicit maintainer decision rather than landing as an incidental Mattermost-local fix.
  • The supplied reproduction is strong for the pure mapper and synthetic event path, but the discussion does not include a live Mattermost server capture that emits a null or blank channel type.

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

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

Labels

channel: mattermost Channel integration: mattermost channel: slack Channel integration: slack size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants