Skip to content

docs: reflect JID identity/equality changes from whatsapp-rust#1182 - #464

Merged
jlucaso1 merged 5 commits into
mainfrom
claude/nifty-bohr-upct1n
Jul 29, 2026
Merged

docs: reflect JID identity/equality changes from whatsapp-rust#1182#464
jlucaso1 merged 5 commits into
mainfrom
claude/nifty-bohr-upct1n

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

whatsapp-rust#1182 ("fix(jid): make agent identity, the AD form, and device dedup agree") changed how Jid/JidRef equality, Hash, and device deduplication work. This PR updates the two docs pages that document that surface so they match the new behavior:

  • advanced/binary-protocol.mdx — The note explaining why a wire-decoded JID equals a text-parsed one previously attributed this solely to the decoder invariant ("agent stays 0"). Jid/JidRef now implement PartialEq/Hash by hand, routed through a private identity_agent() that structurally ignores agent on any server where it isn't rendered — independent of whatever the raw field holds. Updated both the struct-level <Note> and the AD_JID decoding section to describe this as a structural guarantee rather than a decoder-only one, and to mention that integrator is not normalized the same way (folded into identity unconditionally, matching is_same_chat_as) and that Jid::identity_agent() is now public.
  • advanced/signal-protocol.mdxsort_dedup_by_device's doc comment said it keys on "user + server + agent + device". It now keys on Jid::identity_agent() (user + server + device + integrator + identity_agent) to match Jid's own equality rule. Added an explanation of why the old raw-agent key was wrong in both directions: it could merge two devices that genuinely differ (@bot/@interop with a rendered agent) or fail to collapse two JIDs that are actually the same device (an inert agent byte on Pn/Lid/Hosted/HostedLid).

Deliberately not included

Per instructions, changelog entries are human-authored only — changelog/2026-06-10-phash-arena-sort.mdx still references the pre-rename push_ad_to/to_ad_string function names (renamed to push_phash_form_to/to_phash_form_string in #1182), but that file was left untouched.

normalize_for_prekey_bundle, which #1182 removes entirely, was never documented in this repo, so there's nothing to update there.

References


Generated by Claude Code


Summary by cubic

Update Binary and Signal protocol docs to match the new Jid/JidRef identity and device dedup rules from whatsapp-rust#1182. Clarifies hand-written PartialEq/Hash (private identity_agent(server, agent) helper and public Jid::identity_agent()), notes agent is ignored where not rendered and integrator is folded, confirms parsed vs wire JIDs compare/hash equal even with a stray agent, switches sort_dedup_by_device to key on Jid::identity_agent(), and splits the equality note into single-idea sentences per style.

Written for commit 6645a25. Summary will update on new commits.

Summary by CodeRabbit

  • Documentation
    • Clarified how WhatsApp JID identity, equality, and hashing are normalized.
    • Documented consistent handling of agent and integrator identity values across encoding and decoding.
    • Explained that binary protocol round trips preserve normalized identity values.
    • Clarified device deduplication behavior to distinguish device types while ignoring irrelevant agent data.

jlucaso1 added 3 commits July 29, 2026 02:14
Follow-up to whatsapp-rust#1182, which moved Jid/JidRef equality and
Hash off the derived impls onto identity_agent()-routed hand-written
ones. Update the notes explaining why a wire-decoded JID equals a
text-parsed one to describe the structural guarantee instead of the
decoder-only invariant that used to be the whole story.
Follow-up to whatsapp-rust#1182. sort_dedup_by_device now keys on
Jid::identity_agent() (user + server + device + integrator +
identity_agent) instead of the raw agent field, matching the JID's
own hand-written PartialEq/Hash. Explain why both directions of the
old raw-agent key were wrong: it could either merge two rendered-agent
devices or fail to collapse two JIDs that are actually one device.
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Documentation now describes normalized JID identity semantics across binary decoding, equality, hashing, and signal-protocol device deduplication. It also explains how identity_agent() prevents inconsistencies from stray agent values.

Changes

JID identity semantics

Layer / File(s) Summary
JID equality and decoder contract
advanced/binary-protocol.mdx
Documents normalized agent handling, hand-written PartialEq/Hash behavior, public identity_agent(), integrator identity handling, and decode/encode consistency.
Device deduplication key
advanced/signal-protocol.mdx
Clarifies that sort_dedup_by_device deduplicates using Jid::identity_agent() rather than the raw agent field.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Poem

I’m a rabbit with a JID in my ear,
Normalized agents make identities clear.
Hashes now hop in a matching line,
Devices dedup neatly, row by row in time.
Squeak hooray for docs that align!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the documentation update about JID identity and equality changes.

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.

@mintlify

mintlify Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
whatsapp-rust 🟢 Ready View Preview Jul 29, 2026, 5:36 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@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: 2

🤖 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 `@advanced/binary-protocol.mdx`:
- Around line 127-131: Rewrite the documentation at advanced/binary-protocol.mdx
lines 127-131 and advanced/signal-protocol.mdx lines 2009-2013 using concise,
one-idea sentences. In binary-protocol.mdx, separate the normalization behavior,
equality and hashing behavior, integrator handling, and public identity_agent()
guidance. In signal-protocol.mdx, separate the deduplication key, raw agent
failure mode, and Bot/Interop exception. Make no behavioral or API changes.
- Around line 127-131: Update the documentation around Jid and JidRef equality
to describe identity_agent() consistently as public rather than private, and
replace “derived comparisons” with “manual comparisons” when explaining how
callers should apply the same identity rule.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 648563fc-18d5-4515-9c21-f419779be5b3

📥 Commits

Reviewing files that changed from the base of the PR and between 5979059 and bf91aea.

📒 Files selected for processing (2)
  • advanced/binary-protocol.mdx
  • advanced/signal-protocol.mdx

Comment thread advanced/binary-protocol.mdx Outdated
Comment on lines +127 to +131
Earlier versions kept a redundant copy in `agent`. If you decoded a JID off the wire, you got `agent` set to the domain byte; if you parsed the same JID from text, you got `agent` set to `0` — even though `Display` rendered both the same way. With `PartialEq`/`Hash` derived at the time, those two JIDs compared unequal and could hash to different values.

`agent` now stays `0` for these servers on both paths, so a wire-decoded JID and a text-parsed JID compare equal and hash the same. `agent` is only ever nonzero for `Bot`/`Interop`, which do render it.
`agent` now stays `0` for these servers on both paths, so a wire-decoded JID and a text-parsed JID compare equal and hash the same. But `PartialEq`/`Hash` no longer *rely* on that invariant holding everywhere either — `Jid` and `JidRef` implement both by hand, routed through a private `identity_agent()` that reads as `0` on any server where `Server::renders_agent()` is false, regardless of what the raw field holds. That closes a gap the decoder fix alone didn't: `swap_pn_lid_namespace` and similar code can still carry a nonzero `agent` across a namespace conversion, and equality treats the result the same as the clean JID either way. `agent` is only ever identity-relevant for `Bot`/`Interop`, which do render it.

`integrator` is *not* normalized the same way — it is folded into identity unconditionally, matching `is_same_chat_as`, since the field is never set outside `Interop` in practice. `Jid::identity_agent()` is public so code building its own key over a JID (sorting, deduplicating, indexing) can apply the same rule the derived comparisons use instead of reading `jid.agent` directly.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use concise, one-idea sentences in both documentation updates.

  • advanced/binary-protocol.mdx#L127-L131: split normalization, equality/hashing, integrator behavior, and public API guidance into separate sentences.
  • advanced/signal-protocol.mdx#L2009-L2013: split the deduplication key, raw-agent failure mode, and Bot/Interop exception into separate sentences.

As per coding guidelines, keep sentences concise — one idea per sentence in documentation.

📍 Affects 2 files
  • advanced/binary-protocol.mdx#L127-L131 (this comment)
  • advanced/signal-protocol.mdx#L2009-L2013
🤖 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 `@advanced/binary-protocol.mdx` around lines 127 - 131, Rewrite the
documentation at advanced/binary-protocol.mdx lines 127-131 and
advanced/signal-protocol.mdx lines 2009-2013 using concise, one-idea sentences.
In binary-protocol.mdx, separate the normalization behavior, equality and
hashing behavior, integrator handling, and public identity_agent() guidance. In
signal-protocol.mdx, separate the deduplication key, raw agent failure mode, and
Bot/Interop exception. Make no behavioral or API changes.

Source: Coding guidelines


🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -A8 -B4 'identity_agent' wacore/binary/src/jid.rs

Repository: oxidezap/whatsapp-rust-docs

Length of output: 286


🏁 Script executed:

#!/bin/bash
set -u

echo "Repository files matching binary/jid docs:"
git ls-files | rg -n '(^|/)advanced/binary-protocol\.mdx$|jid\.rs$' || true

echo
echo "Locate identity_agent in relevant tracked files:"
rg -n 'identity_agent|renders_agent|PartialEq|Hash|JidRef|identity' -g 'advanced/binary-protocol.mdx' -g '*.rs' . || true

Repository: oxidezap/whatsapp-rust-docs

Length of output: 5547


🏁 Script executed:

#!/bin/bash
set -u

# Inspect the referenced documentation section and nearby context.
sed -n '118,136p' advanced/binary-protocol.mdx | cat -n
printf '\n--- later JID section ---\n'
sed -n '538,552p' advanced/binary-protocol.mdx | cat -n

Repository: oxidezap/whatsapp-rust-docs

Length of output: 4992


Make the identity_agent() API description internally consistent.

Line 131 says Jid::identity_agent() is public, while line 129 describes it as a private helper. Also replace “derived comparisons” with “manual comparisons” because the text says the implementations are hand-written.

🤖 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 `@advanced/binary-protocol.mdx` around lines 127 - 131, Update the
documentation around Jid and JidRef equality to describe identity_agent()
consistently as public rather than private, and replace “derived comparisons”
with “manual comparisons” when explaining how callers should apply the same
identity rule.

@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: bf91aea848

ℹ️ 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 thread advanced/binary-protocol.mdx Outdated
Earlier versions kept a redundant copy in `agent`. If you decoded a JID off the wire, you got `agent` set to the domain byte; if you parsed the same JID from text, you got `agent` set to `0` — even though `Display` rendered both the same way. With `PartialEq`/`Hash` derived at the time, those two JIDs compared unequal and could hash to different values.

`agent` now stays `0` for these servers on both paths, so a wire-decoded JID and a text-parsed JID compare equal and hash the same. `agent` is only ever nonzero for `Bot`/`Interop`, which do render it.
`agent` now stays `0` for these servers on both paths, so a wire-decoded JID and a text-parsed JID compare equal and hash the same. But `PartialEq`/`Hash` no longer *rely* on that invariant holding everywhere either — `Jid` and `JidRef` implement both by hand, routed through a private `identity_agent()` that reads as `0` on any server where `Server::renders_agent()` is false, regardless of what the raw field holds. That closes a gap the decoder fix alone didn't: `swap_pn_lid_namespace` and similar code can still carry a nonzero `agent` across a namespace conversion, and equality treats the result the same as the clean JID either way. `agent` is only ever identity-relevant for `Bot`/`Interop`, which do render it.

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 Describe the identity helper's visibility consistently

When readers want to build custom sort or index keys, this sentence says identity_agent() is private, while the next paragraph explicitly presents Jid::identity_agent() as public for that exact use. This leaves the documented API contradictory; describe the Jid method as public here, or qualify which separate helper remains private.

Useful? React with 👍 / 👎.

pub fn sort_dedup_by_device(jids: &mut Vec<Jid>);
```

`sort_dedup_by_device` keys on `Jid::identity_agent()` rather than the raw `agent` field, so its notion of "same device" matches exactly what `Jid`'s `PartialEq`/`Hash` already treat as equal (see [Binary Protocol](/advanced/binary-protocol#jid-encoding) for why the two fields differ). That has to hold in both directions: keying on the raw `agent` would let two JIDs that are actually one device — an inert agent byte on `Pn`/`Lid`/`Hosted`/`HostedLid`, same AD-JID, same Signal address — both survive the dedup and pick up two concurrent encryption jobs against one session; dropping `agent` from the key entirely would go too far the other way and silently collapse two genuinely distinct `@bot`/`@interop` devices, which *do* render it, losing a fan-out destination.

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 Split the device-dedup explanation into concise sentences

This added sentence combines the chosen key, its equality rationale, the duplicate-encryption consequence, and the Bot/Interop counterexample into one very long sentence. Split these into concise, one-idea sentences so readers can follow the two distinct failure modes and the page complies with the project's writing standard.

AGENTS.md reference: AGENTS.md:L25-L25

Useful? React with 👍 / 👎.

CodeRabbit review on #464: the note called identity_agent() "private"
in one sentence, then said Jid::identity_agent() "is public" two
sentences later, without distinguishing that these are two different
items — a private module-level free function and a public method
that wraps it. Clarify both are separate but related.
CodeRabbit and Codex both flagged the JID-equality note as running
multiple ideas per sentence, against this repo's documented style rule
("keep sentences concise — one idea per sentence", AGENTS.md). Break
the note into single-idea sentences without changing its content.
@jlucaso1
jlucaso1 merged commit dace5a8 into main Jul 29, 2026
3 checks passed
jlucaso1 added a commit that referenced this pull request Jul 29, 2026
Codex review on PR #464 flagged the added explanation of why
sort_dedup_by_device keys on identity_agent() as combining the key
choice, equality rationale, duplicate-encryption consequence, and the
Bot/Interop counterexample into one long sentence — against this
repo's AGENTS.md style rule ('keep sentences concise — one idea per
sentence'). Split it into single-idea sentences without changing the
content.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant