Skip to content

fix(discord): canonicalize PluralKit inbound ids#55413

Closed
acgh213 wants to merge 4 commits into
openclaw:mainfrom
acgh213:fix/pk-canonical-inbound
Closed

fix(discord): canonicalize PluralKit inbound ids#55413
acgh213 wants to merge 4 commits into
openclaw:mainfrom
acgh213:fix/pk-canonical-inbound

Conversation

@acgh213

@acgh213 acgh213 commented Mar 26, 2026

Copy link
Copy Markdown

Summary

Canonicalize Discord inbound message ids for PluralKit-routed messages by using the PluralKit original message id when available.

What changed

  • always perform PluralKit lookup when Discord PluralKit integration is enabled, including for webhook-authored messages
  • thread canonicalMessageId through Discord preflight context
  • set Discord inbound MessageSid to the PluralKit original id when present
  • preserve the actual provider message id in MessageSidFull
  • add regression coverage for webhook-authored PK preflight handling and canonical inbound id mapping

Why

The earlier withdrawn approach tried to reduce duplicate turn pressure with broader webhook suppression and heuristic clone dedupe. This replacement takes a narrower provenance-driven path instead:

  • original Discord user-authored message and PluralKit webhook-proxied copy should collapse to the same canonical inbound id when PluralKit provides that mapping
  • this keeps generic inbound dedupe message-id-based rather than shifting toward normalized-content heuristics
  • legitimate webhook traffic is not broadly suppressed just for being webhook-authored in a bound thread

Validation

Ran:

corepack pnpm exec vitest run \
  extensions/discord/src/pluralkit.test.ts \
  extensions/discord/src/monitor/message-handler.preflight.test.ts \
  extensions/discord/src/monitor/message-handler.process.test.ts \
  extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts \
  extensions/discord/src/monitor/reply-delivery.test.ts

All passed.

Notes

  • MessageSidFull still preserves the actual provider message id for downstream consumers that need the concrete Discord message id
  • this does not broaden webhook suppression behavior; it changes canonical inbound identity instead

@openclaw-barnacle openclaw-barnacle Bot added channel: discord Channel integration: discord size: S labels Mar 26, 2026
@greptile-apps

greptile-apps Bot commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a bug where PluralKit-proxied webhook messages were excluded from the PluralKit API lookup (due to a !webhookId guard), preventing correct canonical message ID deduplication. The fix removes that guard so all messages trigger a PK lookup when PK is enabled, threads canonicalMessageId from pluralkitInfo.original through the preflight context, and maps MessageSid to the canonical ID in the process step — with MessageSidFull preserving the actual Discord message ID. This allows the original user-authored message and its PK webhook-proxied copy to collapse to the same MessageSid, enabling upstream deduplication without content-heuristics.

Key changes:

  • Removes && !webhookId from shouldCheckPluralKit, so webhook-authored messages are now included in PK lookups when PK is enabled
  • Adds canonicalMessageId?: string to DiscordMessagePreflightContext and populates it from pluralkitInfo?.original?.trim()
  • Uses canonicalMessageId || message.id for MessageSid and always sets MessageSidFull = message.id
  • Adds webhookId to createDiscordMessage test helper
  • Adds regression tests covering PK preflight for webhook-authored messages and the canonical ID mapping in the process step

One consequence worth monitoring: removing the !webhookId guard means every incoming message (including non-PK webhook messages such as GitHub or CI bot postings) will now make an additional HTTP request to the PluralKit API, which will return a 404 and resolve to null gracefully. This is a deliberate design trade-off explained in the PR description, but in high-traffic Discord servers with many non-PK integrations, PK API rate limits or latency impact may be worth watching.

Confidence Score: 5/5

Safe to merge — the fix is narrowly scoped, logically correct, and well-covered by new tests.

No correctness issues found. The removal of the !webhookId guard is the intended fix; the 404 → null path for non-PK messages is already properly handled. canonicalMessageId propagation is clean, the fallback to message.id is correct, and the new MessageSidFull field is additive. The increased PK API call volume for non-PK webhook messages is an acknowledged, documented trade-off, not a bug.

No files require special attention.

Important Files Changed

Filename Overview
extensions/discord/src/monitor/message-handler.preflight.ts Removes !webhookId guard from shouldCheckPluralKit and adds canonicalMessageId to the returned context from pluralkitInfo.original
extensions/discord/src/monitor/message-handler.preflight.types.ts Adds optional canonicalMessageId field to DiscordMessagePreflightContext
extensions/discord/src/monitor/message-handler.process.ts Destructures canonicalMessageId from ctx, uses it for MessageSid with message.id fallback, always sets MessageSidFull to message.id
extensions/discord/src/monitor/message-handler.preflight.test.ts Adds mock for fetchPluralKitMessageInfo and a new test verifying canonical original id is preserved for webhook-authored PK messages
extensions/discord/src/monitor/message-handler.process.test.ts Expands getLastDispatchCtx to track MessageSid/MessageSidFull and adds test verifying PK original id is used as MessageSid
extensions/discord/src/monitor/message-handler.preflight.test-helpers.ts Adds optional webhookId param to createDiscordMessage helper

Reviews (1): Last reviewed commit: "fix(discord): canonicalize PluralKit inb..." | Re-trigger Greptile

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

Copy link
Copy Markdown

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: 6e953587cd

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 267 to 270
const shouldCheckPluralKit = Boolean(pluralkitConfig?.enabled);
let pluralkitInfo: Awaited<ReturnType<typeof fetchPluralKitMessageInfo>> = null;
if (shouldCheckPluralKit) {
try {

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 PK lookup before webhook-echo suppression

When discord.pluralkit.enabled is true, shouldCheckPluralKit now ignores webhookId, so webhook-authored messages always call fetchPluralKitMessageInfo before preflight reaches the later bound-thread webhook suppression (shouldIgnoreBoundThreadWebhookMessage). In active bound-thread sessions this causes OpenClaw’s own webhook echo messages (which are dropped anyway) to still incur an external PluralKit API request, adding avoidable latency and rate-limit/log noise for no functional gain.

Useful? React with 👍 / 👎.

@acgh213

acgh213 commented Mar 27, 2026

Copy link
Copy Markdown
Author

Addressed the Codex feedback about unnecessary PK polling on our own bound-thread webhook echoes.

What changed in the latest push:

  • bound-thread webhook echo suppression now happens before the PK lookup
  • known OpenClaw webhook echoes are dropped without calling the PK API
  • PK lookup still runs for non-echo webhook-authored messages, so PluralKit proxy copies can still provide original for canonical inbound identity
  • added regression coverage asserting that hydrated bound-thread webhook echoes do not call fetchPluralKitMessageInfo

Local validation after the change:

corepack pnpm exec vitest run \
  extensions/discord/src/monitor/message-handler.preflight.test.ts \
  extensions/discord/src/monitor/message-handler.process.test.ts \
  extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts \
  extensions/discord/src/monitor/reply-delivery.test.ts \
  extensions/discord/src/monitor/provider.test.ts

Result: 5 files passed, 116 tests passed.

@acgh213 acgh213 force-pushed the fix/pk-canonical-inbound branch from e211232 to 043c625 Compare March 27, 2026 14:47

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

Copy link
Copy Markdown

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: 043c625c63

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +470 to +475
if (pluralkitConfig?.enabled) {
try {
pluralkitInfo = await fetchPluralKitMessageInfo({
messageId: message.id,
config: pluralkitConfig,
});

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 Run PluralKit identity lookup before bot-drop gate

The PluralKit lookup now happens only after the early bot gate, so allowBots=false messages can be discarded before sender.isPluralKit is ever resolved. In practice, if a webhook-authored PK message arrives without webhookId in the event payload (or hydration fails and we keep the partial payload), this path drops the message at the bot check and never reaches the lookup that would classify it as PK. This is a regression from the previous ordering, where lookup could still rescue bot-authored PK traffic in that degraded-payload scenario.

Useful? React with 👍 / 👎.

@clawsweeper

clawsweeper Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge.

Summary
The PR looks up PluralKit metadata for webhook-authored Discord messages, carries the PluralKit original id through preflight, uses it as inbound MessageSid, preserves the provider id as MessageSidFull, and adds regression tests.

Reproducibility: yes. A focused current-main check shows webhook-authored messages return no PluralKit info because webhookId short-circuits the helper, and the inbound context still uses the provider message.id as MessageSid.

Next step before merge
An automated repair can make the narrow rebase and ordering/context/changelog fixes without a broader product decision.

Security
Cleared: The diff is limited to Discord inbound processing and tests, with no dependency, workflow, package, release, secret-handling, or executable supply-chain changes.

Review findings

  • [P2] Move PluralKit lookup before bot-drop gates — extensions/discord/src/monitor/message-handler.preflight.ts:466
  • [P2] Rebase MessageSid mapping into the context builder — extensions/discord/src/monitor/message-handler.process.ts:390-391
  • [P3] Add the required changelog entry — CHANGELOG.md:31
Review details

Best possible solution:

Land a rebased Discord fix that filters known OpenClaw bound-thread webhook echoes before external PK calls, performs PK lookup for every other PK-enabled inbound message before bot gates, carries a trimmed original id through preflight, maps MessageSid/MessageSidFull in buildDiscordMessageProcessContext, and adds focused tests plus a changelog entry.

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

Yes. A focused current-main check shows webhook-authored messages return no PluralKit info because webhookId short-circuits the helper, and the inbound context still uses the provider message.id as MessageSid.

Is this the best way to solve the issue?

No. The provenance-driven canonical id approach is the right narrow fix, but this PR needs the lookup ordering corrected and the mapping rebased into the current message-handler.context.ts builder before merge.

Full review comments:

  • [P2] Move PluralKit lookup before bot-drop gates — extensions/discord/src/monitor/message-handler.preflight.ts:466
    The new lookup block runs after earlier bot filtering, so a PK proxy copy with a missing or unhydrated webhookId can still be dropped before sender.isPluralKit is resolved. Keep known bound-thread webhook echo suppression before the external call, then run PK lookup for other PK-enabled messages before bot gates.
    Confidence: 0.87
  • [P2] Rebase MessageSid mapping into the context builder — extensions/discord/src/monitor/message-handler.process.ts:390-391
    Current main builds the Discord dispatch context in message-handler.context.ts, while this PR changes the older inline context construction in process.ts. Move the canonical MessageSid and provider MessageSidFull mapping into buildDiscordMessageProcessContext or the rebased patch will keep dispatching the provider id.
    Confidence: 0.85
  • [P3] Add the required changelog entry — CHANGELOG.md:31
    This is a user-facing Discord fix, but the PR does not add an Unreleased changelog bullet. Add a single-line CHANGELOG.md entry for the canonical PluralKit inbound id behavior with appropriate contributor credit.
    Confidence: 0.82

Overall correctness: patch is incorrect
Overall confidence: 0.88

Acceptance criteria:

  • pnpm test extensions/discord/src/pluralkit.test.ts extensions/discord/src/monitor/message-handler.preflight.test.ts extensions/discord/src/monitor/message-handler.process.test.ts extensions/discord/src/monitor/message-handler.inbound-context.test.ts extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts extensions/discord/src/monitor/reply-delivery.test.ts
  • pnpm exec oxfmt --check --threads=1 extensions/discord/src/monitor/message-handler.preflight.ts extensions/discord/src/monitor/message-handler.preflight-pluralkit.ts extensions/discord/src/monitor/message-handler.preflight.types.ts extensions/discord/src/monitor/message-handler.context.ts extensions/discord/src/monitor/message-handler.preflight.test.ts extensions/discord/src/monitor/message-handler.process.test.ts extensions/discord/src/monitor/message-handler.inbound-context.test.ts extensions/discord/src/monitor/message-handler.preflight.test-helpers.ts CHANGELOG.md
  • pnpm check:changed

What I checked:

Likely related people:

  • thewilloftheshadow: Related merged PR Discord: add PluralKit sender identity resolver #5838 added the Discord PluralKit lookup and sender identity resolver that this PR extends. (role: introduced PluralKit feature; confidence: medium; commits: a1cf76e442ff; files: extensions/discord/src/pluralkit.ts, extensions/discord/src/monitor/sender-identity.ts, docs/channels/discord.md)
  • Peter Steinberger: Local blame on the current extracted preflight helper, preflight flow, and context builder points to the recent refactor: trim subagent followup facade restructuring. (role: recent maintainer/refactor owner; confidence: medium; commits: 0e7cebc5c65f, b8ddb8a494b2; files: extensions/discord/src/monitor/message-handler.preflight-pluralkit.ts, extensions/discord/src/monitor/message-handler.preflight.ts, extensions/discord/src/monitor/message-handler.context.ts)
  • acgh213: Current changelog credits related Discord thread/PluralKit duplicate-pressure work in Discord bound threads can double-handle PluralKit messages #52005, so they likely have useful context beyond being this PR's author. (role: adjacent Discord PluralKit contributor; confidence: medium; files: CHANGELOG.md, extensions/discord/src/monitor/message-handler.preflight.ts)

Remaining risk / open question:

  • The repair must preserve the shipped bound-thread webhook echo suppression from Discord bound threads can double-handle PluralKit messages #52005 while allowing non-echo webhook-authored PluralKit proxy copies to resolve original.
  • The PR branch is stale against the current Discord context-builder refactor, so line locations will move during rebase.

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

@steipete

steipete commented May 2, 2026

Copy link
Copy Markdown
Contributor

Thanks @acgh213. I landed the equivalent fix on main in 70dcd81f03 after rechecking the PluralKit API contract and current inbound dedupe/reply paths. Closing this PR as superseded.

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

Labels

channel: discord Channel integration: discord size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants