Skip to content

fix: emit labels.association remove event for tombstone mutations#2650

Open
ropic wants to merge 1 commit into
WhiskeySockets:masterfrom
ropic:fix/label-remove-tombstone-events
Open

fix: emit labels.association remove event for tombstone mutations#2650
ropic wants to merge 1 commit into
WhiskeySockets:masterfrom
ropic:fix/label-remove-tombstone-events

Conversation

@ropic

@ropic ropic commented Jun 19, 2026

Copy link
Copy Markdown

WhatsApp sends label REMOVE operations as tombstone mutations: the mutation has operation=REMOVE but an empty labelAssociationAction field. The existing handler only checks action?.labelAssociationAction (undefined for tombstones) and falls through to "unprocessable update", so label removal events are never emitted.

Two changes:

  1. decodeSyncdMutations: include operation in the onMutation callback object so processSyncAction can access it. Requires adding operation as an optional field to the ChatMutation type.
  2. processSyncAction: add a handler for tombstone REMOVE mutations on label_jid associations that emits labels.association with type:remove.

Tested on Baileys 7.0.0-rc.9 with WhatsApp mobile (iOS/Android).


Summary by cubic

Fixes missing label removal events by handling WhatsApp tombstone REMOVE mutations. Now emits labels.association with type: remove when a label is removed.

  • Bug Fixes
    • Include mutation operation in decodeSyncdMutations and add it to ChatMutation.
    • Handle tombstone REMOVE on label_jid in processSyncAction and emit labels.association with type: remove.

Written for commit 61b08cb. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved label removal synchronization to properly handle deletion of labels from chats and maintain accurate label associations across the system.

WhatsApp sends label REMOVE operations as tombstone mutations: the
mutation has operation=REMOVE but an empty labelAssociationAction
field. The existing handler only checks action?.labelAssociationAction
(undefined for tombstones) and falls through to "unprocessable update",
so label removal events are never emitted.

Two changes:
1. decodeSyncdMutations: include operation in the onMutation callback
   object so processSyncAction can access it. Requires adding operation
   as an optional field to the ChatMutation type.
2. processSyncAction: add a handler for tombstone REMOVE mutations on
   label_jid associations that emits labels.association with type:remove.

Tested on Baileys 7.0.0-rc.9 with WhatsApp mobile (iOS/Android).
@whiskeysockets-bot

Copy link
Copy Markdown
Contributor

Thanks for opening this pull request and contributing to the project!

The next step is for the maintainers to review your changes. If everything looks good, it will be approved and merged into the main branch.

In the meantime, anyone in the community is encouraged to test this pull request and provide feedback.

✅ How to confirm it works

If you’ve tested this PR, please comment below with:

Tested and working ✅

This helps us speed up the review and merge process.

📦 To test this PR locally:

# NPM
npm install @whiskeysockets/baileys@ropic/Baileys#fix/label-remove-tombstone-events

# Yarn (v2+)
yarn add @whiskeysockets/baileys@ropic/Baileys#fix/label-remove-tombstone-events

# PNPM
pnpm add @whiskeysockets/baileys@ropic/Baileys#fix/label-remove-tombstone-events

If you encounter any issues or have feedback, feel free to comment as well.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

ChatMutation gains an optional operation field typed as proto.SyncdMutation.SyncdOperation. decodeSyncdMutations now includes this field when invoking onMutation. processSyncAction destructures operation and adds a branch that emits a labels.association remove event when a syncd REMOVE tombstone targets a Chat-type label association.

Changes

Chat-label REMOVE tombstone support

Layer / File(s) Summary
ChatMutation operation field
src/Types/Chat.ts
Adds operation?: proto.SyncdMutation.SyncdOperation as an optional field on the ChatMutation type.
Forward operation and handle REMOVE tombstones
src/Utils/chat-utils.ts
decodeSyncdMutations passes the syncd mutation operation into the onMutation callback. processSyncAction destructures operation and, when it is REMOVE and the label association type is Chat, emits a labels.association event with type: 'remove', chatId, and labelId derived from the tombstone index.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 A label was lost, but now we take note,
The REMOVE tombstone gets its own vote.
operation travels from decode to sync,
Chat-label departures no longer just sink.
Hop hop! The event bus knows when things go. 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding event emission for label removal in tombstone mutations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Utils/chat-utils.ts`:
- Around line 969-981: The tombstone REMOVE label dissociation path in the
chat-utils.ts file (where operation ===
proto.SyncdMutation.SyncdOperation.REMOVE and type ===
LabelAssociationType.Chat) currently lacks test coverage. Add a test case in
src/__tests__/Utils/process-sync-action.test.ts that exercises this specific
code path by setting up a test scenario with operation=REMOVE and
type=LabelAssociationType.Chat, then verify that the
ev.emit('labels.association', { type: 'remove', ... }) call is triggered
correctly with the appropriate ChatLabelAssociation payload.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2911bde9-4674-4718-aba5-59b6baff955c

📥 Commits

Reviewing files that changed from the base of the PR and between 75d6588 and 61b08cb.

📒 Files selected for processing (2)
  • src/Types/Chat.ts
  • src/Utils/chat-utils.ts

Comment thread src/Utils/chat-utils.ts
Comment on lines +969 to +981
} else if (
operation === proto.SyncdMutation.SyncdOperation.REMOVE &&
type === LabelAssociationType.Chat
) {
// Tombstone REMOVE: WhatsApp sends label removals with operation=REMOVE and empty labelAssociationAction
ev.emit('labels.association', {
type: 'remove',
association: {
type: LabelAssociationType.Chat,
chatId: msgId!,
labelId: id!
} as ChatLabelAssociation
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Find processSyncAction tests
fd -i 'process-sync-action*.test.ts' src/__tests__ src | sed 's#^`#TEST_FILE`: #'

# 2) Search for REMOVE tombstone coverage around labels.association remove emissions
rg -n -C3 --type=ts \
  "SyncdOperation\.REMOVE|labelAssociation|labels\.association|type:\s*'remove'|LabelAssociationType\.Chat" \
  src/__tests__ src | sed 's#^`#MATCH`: #'

Repository: WhiskeySockets/Baileys

Length of output: 13317


🏁 Script executed:

cat src/__tests__/Utils/process-sync-action.test.ts | head -300

Repository: WhiskeySockets/Baileys

Length of output: 10134


🏁 Script executed:

sed -n '260,350p' src/__tests__/Utils/process-sync-action.test.ts

Repository: WhiskeySockets/Baileys

Length of output: 3545


🏁 Script executed:

wc -l src/__tests__/Utils/process-sync-action.test.ts

Repository: WhiskeySockets/Baileys

Length of output: 118


🏁 Script executed:

sed -n '295,359p' src/__tests__/Utils/process-sync-action.test.ts

Repository: WhiskeySockets/Baileys

Length of output: 2668


Add integration test for tombstone REMOVE label dissociation

The labelAssociationAction tests cover labeled: true (ADD) cases. Add a test in src/__tests__/Utils/process-sync-action.test.ts that exercises the tombstone REMOVE path — operation === REMOVE with type === LabelAssociationType.Chat — and verifies that ev.emit('labels.association', { type: 'remove', ... }) is called correctly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Utils/chat-utils.ts` around lines 969 - 981, The tombstone REMOVE label
dissociation path in the chat-utils.ts file (where operation ===
proto.SyncdMutation.SyncdOperation.REMOVE and type ===
LabelAssociationType.Chat) currently lacks test coverage. Add a test case in
src/__tests__/Utils/process-sync-action.test.ts that exercises this specific
code path by setting up a test scenario with operation=REMOVE and
type=LabelAssociationType.Chat, then verify that the
ev.emit('labels.association', { type: 'remove', ... }) call is triggered
correctly with the appropriate ChatLabelAssociation payload.

Source: Coding guidelines

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

No issues found across 2 files

Re-trigger cubic

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

This PR is stale because it has been open for 14 days with no activity. Remove the stale label or comment or this will be closed in 14 days

@github-actions github-actions Bot added the Stale label Jul 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants