docs: document stanza interceptors, decrypted-payload event, and plugin claim capability - #490
Conversation
…in claim capability Covers the merged whatsapp-rust stack: a client-level seam for claiming a decoded stanza before the built-in pipeline (whatsapp-rust#1239), an Event::DecryptedPayload emitted before decode so an undecodable plaintext isn't lost (whatsapp-rust#1240), and the stanza.intercept plugin capability with panic isolation and terminal invalidation on top of it (whatsapp-rust#1241).
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughThe documentation adds stanza interception APIs and plugin support. It also documents leased forwarding of decrypted payloads through ChangesInterception and decrypted payload flow
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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/plugins.mdx`:
- Line 222: Update the `Client::memory_report()` documentation to use only the
documented public `MemoryReport` fields, replacing `plugin_stanza_interceptors`
and `plugin_core_event_subscriptions` with their actual field names. If these
plugin-specific counters are intentionally separate, document them under their
existing public names instead.
- Around line 186-205: Update the interceptor example imports to include
std::sync::Arc, so the Arc::new calls in ClientPlugin::install and related
registration code compile when copied.
In `@api/client.mdx`:
- Line 1858: Rewrite the interceptor and payload-forwarding guidance in
api/client.mdx lines 1858-1858 using active, second-person sentences, one
contract per sentence, and formatted API identifiers such as
StanzaRouter::register. Rewrite the plugin interception guidance in
advanced/plugins.mdx lines 184-184 with the same concise, reader-directed style
and code formatting for code references.
In `@concepts/events.mdx`:
- Around line 2653-2679: Update the DecryptedPayload section in the events
documentation so its heading uses code formatting. Rewrite the enc_index and
payload-lifecycle explanations into concise sentences, with one idea per
sentence, while preserving the established third-person system-description style
throughout.
🪄 Autofix
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: 8970fe3f-7be0-40e5-8315-c40535041454
📒 Files selected for processing (3)
advanced/plugins.mdxapi/client.mdxconcepts/events.mdx
| ### `DecryptedPayload` | ||
|
|
||
| **Emitted:** One decrypted `<enc>` payload, after unpadding and *before* it is decoded into a `wa::Message`. To receive this event, hold a lease from `client.acquire_decrypted_payload_forwarding()` and include `EventKind::DecryptedPayload` in your handler's `interest()`. While no lease is held, nothing is emitted and nothing is cloned. | ||
|
|
||
| ```rust | ||
| #[derive(Debug, Clone, Serialize, bon::Builder)] | ||
| #[non_exhaustive] | ||
| pub struct DecryptedPayload { | ||
| pub info: Arc<MessageInfo>, | ||
| pub enc_index: usize, | ||
| pub enc_type: &'static str, | ||
| #[serde(skip)] | ||
| pub payload: Bytes, | ||
| } | ||
|
|
||
| Event::DecryptedPayload(DecryptedPayload) | ||
| ``` | ||
|
|
||
| **Fields:** | ||
| - `info` — Which message this came from. | ||
| - `enc_index` — Which `<enc>` of the stanza produced these bytes, counting from zero in the order the client enumerates them: the stanza's direct `<enc>` children first, then the ones under `<participants><to>` addressed to this device (the fan-out shape, where one stanza carries a copy per device and only yours is yours to decrypt). This is a position in that concatenation, not a child index or a position within `enc_type`'s bucket — an `<enc>` that produces no payload still consumes its slot, so a consumer correlating a forwarded payload back to its node has to walk the stanza the same way. | ||
| - `enc_type` — The `type` attribute the `<enc>` carried: `msg`, `pkmsg`, `skmsg`, … | ||
| - `payload` — The plaintext, unpadded, exactly as decoding receives it. A `Bytes`, so forwarding it is a refcount bump, not a copy. | ||
|
|
||
| This is a library extension with no WhatsApp Web equivalent. It exists because a plaintext that decrypts but fails to decode is otherwise lost: `handle_decrypted_plaintext` turns bytes into `wa::Message`, and when that decode fails — a field a build predates, a message type it doesn't model — the bytes disappear. Nothing can ask for them again, because opening them already consumed state that won't recur: the Signal ratchet advances, so the same ciphertext will never decrypt a second time. `DecryptedPayload` fires whether or not the decode that follows succeeds, which is the point: the failing case is the one with nothing else to look at. It also enables recording traffic for faithful replay (re-encoding a decoded `Message` does not reproduce the original bytes) and decoding with a newer protobuf than the running build carries. | ||
|
|
||
| It's also emitted on the bot-message-secret path (`msg_secret.rs`), ahead of the same decode, where the secret a `message_secret` payload was opened with is single-use rather than ratchet-advanced — the same "cannot be asked for again" property, for a different reason. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Make the event contract easier to scan.
Format the DecryptedPayload heading as code. Split the enc_index and payload-lifecycle explanations into one-idea sentences. Preserve this page’s established third-person system-description style.
As per coding guidelines, documentation must use concise one-idea sentences and code formatting for code references. Based on learnings, preserve the established third-person style for system descriptions in concepts/events.mdx.
🤖 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 `@concepts/events.mdx` around lines 2653 - 2679, Update the DecryptedPayload
section in the events documentation so its heading uses code formatting. Rewrite
the enc_index and payload-lifecycle explanations into concise sentences, with
one idea per sentence, while preserving the established third-person
system-description style throughout.
Sources: Coding guidelines, Learnings
…field Addresses CodeRabbit findings on PR #490: the stanza-interception plugin example used Arc::new without importing it, and the field-count sentence in advanced/plugins.mdx referenced plugin_stanza_interceptors / plugin_core_event_subscriptions without either being backed by a documented MemoryReport row. Adds the plugin_stanza_interceptors row and drops the unbacked claim about plugin_core_event_subscriptions.
|
Addressed 2 of the 4 CodeRabbit findings in 9bbebe4:
Skipping the other 2 (both "rewrite to active, second-person, one-idea-per-sentence prose"): the dense, third-person, multi-clause style in the new sections ( Generated by Claude Code |
There was a problem hiding this comment.
All reported issues were addressed
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
| Filename | Overview |
|---|---|
| advanced/plugins.mdx | Documents plugin stanza interception, registration lifecycle, panic isolation, diagnostics, and durability responsibilities. |
| api/client.mdx | Adds the interceptor and decrypted-payload lease API references and correctly repairs the previously invalid event-registration example. |
| concepts/events.mdx | Adds the DecryptedPayload event definition, emission semantics, fields, and consumption example. |
Reviews (2): Last reviewed commit: "docs: fix undefined example variable and..." | Re-trigger Greptile
There was a problem hiding this comment.
0 issues found across 2 files (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Requires human review: Auto-approval blocked by 2 unresolved issues from previous reviews.
Re-trigger cubic
…ability names Addresses further review findings on PR #490: - api/client.mdx: acquire_decrypted_payload_forwarding's example registered its handler through an undeclared `bot` after acquiring the lease from `client`; switched to the same self-contained ChannelEventHandler pattern register_handler already uses. Also notes that a narrowed-interest handler needs EventKind::DecryptedPayload back in interest(), matching the caveat already present in concepts/events.mdx. - advanced/plugins.mdx: replaced two capability wire-string references (`stanza.intercept`, `events.core.observe`) that weren't defined anywhere on the page with the actual PluginCapability variant names.
|
Fixed the remaining valid findings from Greptile and cubic in 2d10a46:
Generated by Claude Code |
There was a problem hiding this comment.
0 issues found across 2 files (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Auto-approved: Docs-only change: updates .mdx documentation for already-merged intercept/decrypted-payload/capability features and fixes examples; no runtime code, API, schema, or config behavior changes, so no product or operational tradeoff needs human sign-off.
Re-trigger cubic
Summary
Documents the stacked feature landed across three merged whatsapp-rust PRs (merged together as one unit):
Client::add_stanza_interceptor, theStanzaInterceptortrait, andInterception: a seam to claim a decoded stanza before the built-in pipeline runs, instead of watching an unmodeled tag get nacked.Event::DecryptedPayloadandClient::acquire_decrypted_payload_forwarding, emitted after unpadding and before decode, so a plaintext that decrypts but fails to decode isn't lost.stanza.interceptplugin capability (PluginStanzaInterception), adding panic isolation and terminal invalidation on top of the raw interceptor seam.What changed
api/client.mdx— newadd_stanza_interceptorandacquire_decrypted_payload_forwardingsections under Protocol Operations (signatures, the trait, what an interceptor never sees, the ack rules a claim owes the server, cost, examples), plus astanza_interceptorsrow in theMemoryReporttable.concepts/events.mdx—DecryptedPayloadadded to theEventenum listing, and a new "Decrypted payload events" section documenting its fields (info,enc_index,enc_type,payload) and the two emission sites (the main Signal path and the botmessage_secretpath).advanced/plugins.mdx— newPluginCapability::StanzaInterceptionrow in the capabilities table, a new "Stanza interception" section (panic isolation, terminal invalidation, the Signal-durability warning about a claim being final), diagnostics/health field updates, and the "What's not supported yet" note updated now that ingress interception has shipped.Changelog entries are intentionally left untouched per instructions.
Test plan
#add_stanza_interceptor,#acquire_decrypted_payload_forwarding,#decryptedpayload,#stanza-interception) match the anchors the new headings produce, and checked the new API signatures/struct fields against the actual merged source inoxidezap/whatsapp-rust.🤖 Generated with Claude Code
https://claude.ai/code/session_01JpXj3BCSm29Yx1S3yXcD7K
Generated by Claude Code
Summary by cubic
Documents the stanza interception API, the decrypted-payload event, and the plugin claim capability. Clarifies ordering and ack rules, adds memory stats, and fixes examples and capability names.
New Features
api/client.mdx: Addedadd_stanza_interceptorandacquire_decrypted_payload_forwardingdocs (signatures,StanzaInterceptor/Interception, registration order, what’s never offered, ack behavior, cost notes, examples). Addedstanza_interceptorsandplugin_stanza_interceptorstoMemoryReport.concepts/events.mdx: AddedEvent::DecryptedPayloadwith fields, lease requirement, when it fires (Signal path and botmessage_secret), and an example.advanced/plugins.mdx: AddedPluginCapability::StanzaInterceptionandPluginStanzaInterception::register(RAII registration, panic isolation, terminal invalidation, diagnostics:stanza_interceptors,stanza_interception_panics). Updated “What’s not supported yet.”Bug Fixes
api/client.mdx: Fixed theacquire_decrypted_payload_forwardingexample to use aChannelEventHandler; noted that narrowed-interest handlers must includeEventKind::DecryptedPayload.advanced/plugins.mdx: Replaced wire-string capability names withPluginCapabilityvariants.use std::sync::Arc;in the plugin interception example.plugin_core_event_subscriptions.Written for commit 2d10a46. Summary will update on new commits.
Summary by CodeRabbit