Skip to content

[codex] fix(bluebubbles): dedupe webhook replays without dropping edits#52239

Closed
aidenwildenbadt wants to merge 1 commit intoopenclaw:mainfrom
aidenwildenbadt:codex/refresh-bluebubbles-webhook-replay-dedupe
Closed

[codex] fix(bluebubbles): dedupe webhook replays without dropping edits#52239
aidenwildenbadt wants to merge 1 commit intoopenclaw:mainfrom
aidenwildenbadt:codex/refresh-bluebubbles-webhook-replay-dedupe

Conversation

@aidenwildenbadt
Copy link
Copy Markdown

Summary

This refreshes the old BlueBubbles replay-dedupe PR as a clean branch off current origin/main.

The replacement carries forward the replay/edit handling work from the original branch:

  • replay dedupe keys now account for real edit metadata and reply context
  • updated-message events bypass debounce merging so rapid edits are not collapsed into one body
  • malformed updated-message webhook noise still returns 200 ok instead of creating retry churn

It also folds in the still-live review feedback from the old PR:

  • media-only updated-message payloads are treated as conversational instead of being dropped as noise
  • explicit edit metadata now wins over UUID-churn filtering, so a legitimate UUID-like edit is preserved
  • replay keys now include the webhook event type, which prevents same-text edit reversions from colliding with the original new-message replay key
  • the modern BlueBubbles facade export surface is kept intact while adding the replay dedupe helper export the branch needed

Validation

  • npx vitest run extensions/bluebubbles/src/monitor.test.ts -t "media-only updated-message|UUID edits when explicit edit metadata is present|text reversions back to the original body|canonical UUID churn text|text edits without explicit edit metadata when text changes"
  • npx vitest run extensions/bluebubbles/src/monitor.test.ts -t "attachment identity changes|updated-message events that differ only by edit metadata|updated-message events when reply metadata appears later"
  • commit-time pnpm check / lint hooks passed during git commit

@openclaw-barnacle openclaw-barnacle Bot added channel: bluebubbles Channel integration: bluebubbles size: XL r: too-many-prs Auto-close: author has more than twenty active PRs. labels Mar 22, 2026
@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because the author has more than 10 active PRs in this repo. Please reduce the active PR queue and reopen or resubmit once it is back under the limit. You can close your own PRs to get back under the limit.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 22, 2026

Greptile Summary

This PR refreshes the BlueBubbles webhook replay-dedupe branch off current main, fixing several edge cases in how duplicate and edited messages are handled.

Key changes:

  • buildInboundReplayKey now includes the event type (new-message vs updated-message), edit metadata (itemType, dateEdited), and reply context — preventing same-text edit reversions from colliding with the original send's dedupe key
  • updated-message events bypass debounce coalescing entirely, so a rapid typo-fix edit can't merge its body into the original buffered new-message
  • shouldIgnoreUpdatedNonConversationalEvent filters delivery/playback state noise (UUID churn, empty-no-signal payloads) while explicitly preserving media-only payloads and UUID-text edits that carry real edit metadata
  • Replay lifecycle callbacks (onFlushSuccess / onFlushFailure) wire debounce-flush outcomes back into the pending-key tracking so a failed flush doesn't permanently mark a message as seen, and a pending deferred retry is re-enqueued atomically
  • monitor.ts also now exports _resetBlueBubblesWebhookReplayState for clean test isolation
  • src/plugin-sdk/bluebubbles.ts adds createDedupeCache and beginWebhookRequestPipelineOrReject to the facade surface that monitor.ts imports from
  • The test file is substantially refactored: external helpers are inlined, making each test self-contained; new test cases cover all the edge cases described above

Confidence Score: 5/5

  • Safe to merge — logic is sound, edge cases are well-tested, and the only finding is a trivial duplicate reset call in test setup.
  • The implementation correctly handles all the described scenarios with proper error propagation, atomic state transitions in the retry lifecycle, and thorough test coverage. The peek/check split on the dedupe cache is correct. The retryReenqueuedFromFlushFailure guard properly prevents the .catch handler from clearing the pending key when a retry has already been re-enqueued. The only issue found is a harmless duplicate resetBlueBubblesSelfChatCache() call in beforeEach.
  • No files require special attention.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/bluebubbles/src/monitor.test.ts
Line: 254

Comment:
**Duplicate `resetBlueBubblesSelfChatCache` call in `beforeEach`**

`resetBlueBubblesSelfChatCache()` is called twice in a row at lines 253–254. The second call is a no-op (the cache is already empty), but it looks like an accidental copy-paste.

```suggestion
    resetBlueBubblesSelfChatCache();
```

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

Reviews (1): Last reviewed commit: "fix(bluebubbles): dedupe webhook replays..." | Re-trigger Greptile

_resetBlueBubblesShortIdState();
_resetBlueBubblesWebhookReplayState();
resetBlueBubblesSelfChatCache();
resetBlueBubblesSelfChatCache();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Duplicate resetBlueBubblesSelfChatCache call in beforeEach

resetBlueBubblesSelfChatCache() is called twice in a row at lines 253–254. The second call is a no-op (the cache is already empty), but it looks like an accidental copy-paste.

Suggested change
resetBlueBubblesSelfChatCache();
resetBlueBubblesSelfChatCache();
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/bluebubbles/src/monitor.test.ts
Line: 254

Comment:
**Duplicate `resetBlueBubblesSelfChatCache` call in `beforeEach`**

`resetBlueBubblesSelfChatCache()` is called twice in a row at lines 253–254. The second call is a no-op (the cache is already empty), but it looks like an accidental copy-paste.

```suggestion
    resetBlueBubblesSelfChatCache();
```

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

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: 04ef85f768

ℹ️ 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 +272 to +275
"bluebubbles",
target.account.accountId,
eventType,
message.senderId,
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 Deduplicate equivalent updated-message retries against new-message

If BlueBubbles replays a just-received new-message as an updated-message within the debounce window, this split key makes us process both payloads. buildInboundReplayKey() now bakes eventType into the replay cache key, and the production debouncer flushes the pending new-message before immediately forwarding the non-debounced updated-message (src/auto-reply/inbound-debounce.ts:102-107). In other words, the retry path this patch is trying to suppress still emits two inbound dispatches whenever the replay arrives before the original 500 ms debounce expires.

Useful? React with 👍 / 👎.

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

Labels

channel: bluebubbles Channel integration: bluebubbles r: too-many-prs Auto-close: author has more than twenty active PRs. size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant