Skip to content

fix(discord): prevent wildcard component registration collisions#31213

Merged
steipete merged 2 commits intomainfrom
fix/29229-discord-select-wildcard-routing-clean
Mar 2, 2026
Merged

fix(discord): prevent wildcard component registration collisions#31213
steipete merged 2 commits intomainfrom
fix/29229-discord-select-wildcard-routing-clean

Conversation

@steipete
Copy link
Contributor

@steipete steipete commented Mar 2, 2026

Summary

  • Recreate fix(discord): prevent wildcard component registration collisions #29459 from a clean branch (previous fork PR was auto-closed as dirty by barnacle).
  • Keep original fix scope: distinct internal Discord wildcard registration sentinel IDs for all wildcard handlers.
  • Keep parser compatibility: sentinel IDs and legacy * both resolve to wildcard key.
  • Apply parser consistency follow-up: modal wildcard path now uses shared sentinel helper.

Why

Discord wildcard handlers that shared raw customId="*" could be dropped in dedupe-by-customId runtimes, causing select/user/role/channel/mentionable/modal interactions to fail with Unknown component.

Validation (limited gate)

  • pnpm vitest run src/discord/monitor/agent-components.wildcard.test.ts src/discord/components.test.ts src/discord/monitor/provider.test.ts

Links

SidQin-cyber and others added 2 commits March 2, 2026 03:08
Assign distinct sentinel registration ids to Discord wildcard handlers while preserving wildcard parser keys, so select/menu/modal handlers no longer get dropped on runtimes that dedupe by raw customId.
@cursor
Copy link

cursor bot commented Mar 2, 2026

PR Summary

Medium Risk
Changes how Discord component/modals wildcard handlers register and parse customIds; if the sentinel matching is wrong it could break routing of all interactive components. Scope is small but touches core interaction dispatch paths.

Overview
Prevents Discord component interactions from being dropped by dedupe-on-customId runtimes by replacing shared wildcard registrations (customId="*") with distinct sentinel customIds for each component type (button/select variants/modal).

Updates the Carbon customId parsers to treat both legacy "*" and the new sentinel IDs as wildcard keys, and adds a focused Vitest regression suite to ensure sentinel uniqueness and parser compatibility. Also records the fix in CHANGELOG.md.

Written by Cursor Bugbot for commit c35cb2f. This will update automatically on new commits. Configure here.

@openclaw-barnacle openclaw-barnacle bot added channel: discord Channel integration: discord size: S maintainer Maintainer-authored PR labels Mar 2, 2026
@steipete steipete merged commit efd303d into main Mar 2, 2026
13 checks passed
@steipete steipete deleted the fix/29229-discord-select-wildcard-routing-clean branch March 2, 2026 03:08
@steipete
Copy link
Contributor Author

steipete commented Mar 2, 2026

Landed via clean rebase replacement for #29459.

  • Gate: pnpm vitest run src/discord/monitor/agent-components.wildcard.test.ts src/discord/components.test.ts src/discord/monitor/provider.test.ts
  • Land commits: 7e02cccd2228ee615fce9ca38c145cc6fa48bf88, c35cb2f534a153c253a8364953bd0645bce25b19
  • Merge commit: efd303dbc4b90d25afbf2309786644d32c23f882

Thanks @Sid-Qin.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 2, 2026

Greptile Summary

This PR fixes a component registration collision bug in the Discord integration where all wildcard handlers shared the same raw customId = "*", causing deduplication logic to silently drop handlers for select menus, user/role/channel/mentionable selects, and modals (resulting in "Unknown component" errors).

Changes:

  • Assigns a distinct sentinel customId (e.g., __openclaw_discord_component_button_wildcard__) to each of the 7 wildcard component classes in agent-components.ts, eliminating deduplication collisions.
  • Adds isDiscordComponentWildcardRegistrationId() regex helper in components.ts to recognize all sentinel IDs and maps them to wildcard key "*" in both parseDiscordComponentCustomIdForCarbon and parseDiscordModalCustomIdForCarbon. Backward compatibility with the literal "*" is preserved.
  • Adds a new test file (agent-components.wildcard.test.ts) that verifies all 7 sentinels are unique and that both sentinel IDs and real runtime interaction IDs resolve to "*" through their respective parsers.
  • Changelog entry credits original contributor (@Sid-Qin).

Confidence Score: 5/5

  • This PR is safe to merge — it is a minimal, targeted fix with good test coverage and no changes to runtime interaction handling logic.
  • The fix is narrowly scoped: it only changes registration-time sentinel IDs and adds a regex check in the parsers. The regex cannot match real Discord custom IDs (which start with occomp: or ocmodal:), backward compatibility with "*" is preserved, all 7 component types are covered, and the new test suite directly validates both the uniqueness invariant and the wildcard resolution path.
  • No files require special attention.

Last reviewed commit: c35cb2f

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile


for (const component of components) {
expect(component.customIdParser(component.customId).key).toBe("*");
if (component.customId.includes("_modal_")) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Fragile modal detection via includes("_modal_")

The test distinguishes modal components from non-modal ones using component.customId.includes("_modal_"). This implicitly couples the test logic to the naming convention of the sentinel IDs. If the modal sentinel were ever renamed (e.g., to __openclaw_discord_component_dialog_wildcard__) this check would silently fail to invoke the modal-branch assertion, potentially masking a regression.

Consider asserting on the exact sentinel strings instead:

Suggested change
if (component.customId.includes("_modal_")) {
if (component.customIdParser === parseDiscordModalCustomIdForCarbon || component.customId === "__openclaw_discord_component_modal_wildcard__") {

Or, alternatively, export a constant for the modal sentinel ID and reference it directly in the test.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/discord/monitor/agent-components.wildcard.test.ts
Line: 51

Comment:
**Fragile modal detection via `includes("_modal_")`**

The test distinguishes modal components from non-modal ones using `component.customId.includes("_modal_")`. This implicitly couples the test logic to the naming convention of the sentinel IDs. If the modal sentinel were ever renamed (e.g., to `__openclaw_discord_component_dialog_wildcard__`) this check would silently fail to invoke the modal-branch assertion, potentially masking a regression.

Consider asserting on the exact sentinel strings instead:

```suggestion
      if (component.customIdParser === parseDiscordModalCustomIdForCarbon || component.customId === "__openclaw_discord_component_modal_wildcard__") {
```

Or, alternatively, export a constant for the modal sentinel ID and reference it directly in the test.

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

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

Labels

channel: discord Channel integration: discord maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Discord Components V2: Select menus fail — wildcard registration collision in Carbon ComponentHandler

2 participants