Skip to content

docs: document stanza interceptors, decrypted-payload event, and plugin claim capability - #490

Merged
jlucaso1 merged 3 commits into
mainfrom
claude/nifty-bohr-kaih11
Aug 8, 2026
Merged

docs: document stanza interceptors, decrypted-payload event, and plugin claim capability#490
jlucaso1 merged 3 commits into
mainfrom
claude/nifty-bohr-kaih11

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Documents the stacked feature landed across three merged whatsapp-rust PRs (merged together as one unit):

  • whatsapp-rust#1239Client::add_stanza_interceptor, the StanzaInterceptor trait, and Interception: a seam to claim a decoded stanza before the built-in pipeline runs, instead of watching an unmodeled tag get nacked.
  • whatsapp-rust#1240Event::DecryptedPayload and Client::acquire_decrypted_payload_forwarding, emitted after unpadding and before decode, so a plaintext that decrypts but fails to decode isn't lost.
  • whatsapp-rust#1241 — the stanza.intercept plugin capability (PluginStanzaInterception), adding panic isolation and terminal invalidation on top of the raw interceptor seam.

What changed

  • api/client.mdx — new add_stanza_interceptor and acquire_decrypted_payload_forwarding sections under Protocol Operations (signatures, the trait, what an interceptor never sees, the ack rules a claim owes the server, cost, examples), plus a stanza_interceptors row in the MemoryReport table.
  • concepts/events.mdxDecryptedPayload added to the Event enum 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 bot message_secret path).
  • advanced/plugins.mdx — new PluginCapability::StanzaInterception row 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

  • Docs-only change; no build step to run here. Verified cross-references (#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 in oxidezap/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: Added add_stanza_interceptor and acquire_decrypted_payload_forwarding docs (signatures, StanzaInterceptor/Interception, registration order, what’s never offered, ack behavior, cost notes, examples). Added stanza_interceptors and plugin_stanza_interceptors to MemoryReport.
    • concepts/events.mdx: Added Event::DecryptedPayload with fields, lease requirement, when it fires (Signal path and bot message_secret), and an example.
    • advanced/plugins.mdx: Added PluginCapability::StanzaInterception and PluginStanzaInterception::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 the acquire_decrypted_payload_forwarding example to use a ChannelEventHandler; noted that narrowed-interest handlers must include EventKind::DecryptedPayload.
    • advanced/plugins.mdx: Replaced wire-string capability names with PluginCapability variants.
    • Fixed missing use std::sync::Arc; in the plugin interception example.
    • Removed an unbacked reference to plugin_core_event_subscriptions.

Written for commit 2d10a46. Summary will update on new commits.

Summary by CodeRabbit

  • New Features
    • Added optional stanza interception, allowing applications to inspect and selectively handle decoded stanzas before standard processing.
    • Added leased forwarding of decrypted payloads before message decoding, including message metadata and encryption details.
    • Added memory reporting for registered stanza interceptors.
  • Documentation
    • Documented registration, removal, acknowledgement behavior, safety protections, diagnostic counters, and decrypted payload event handling.
    • Removed ingress interception from the list of unsupported features.

…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).
@mintlify

mintlify Bot commented Aug 8, 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 Aug 8, 2026, 1:16 AM

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

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The documentation adds stanza interception APIs and plugin support. It also documents leased forwarding of decrypted payloads through Event::DecryptedPayload, including metadata, lifecycle, and serialization behavior.

Changes

Interception and decrypted payload flow

Layer / File(s) Summary
Stanza interception API and plugin lifecycle
api/client.mdx, advanced/plugins.mdx
Documents ordered interceptor registration, claiming, RAII removal, panic isolation, Signal acknowledgement behavior, plugin capability support, and memory and diagnostic reporting.
Decrypted payload forwarding
concepts/events.mdx, api/client.mdx
Documents the opt-in DecryptedPayload event, lease-gated forwarding, plaintext metadata, zero-copy bytes, and pre-decode emission.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Poem

A rabbit reads stanzas before they flow,
Claims them softly, then lets others go.
Plaintext payloads hop through a lease,
Signal rules keep each message at peace.
DecryptedPayload shines in the moonlight bright.

🚥 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 summarizes the documentation changes for stanza interceptors, decrypted-payload events, and plugin claim capability.

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.

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

📥 Commits

Reviewing files that changed from the base of the PR and between ee1377f and d61e212.

📒 Files selected for processing (3)
  • advanced/plugins.mdx
  • api/client.mdx
  • concepts/events.mdx

Comment thread advanced/plugins.mdx
Comment thread advanced/plugins.mdx Outdated
Comment thread api/client.mdx
Comment thread concepts/events.mdx
Comment on lines +2653 to +2679
### `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.

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 | 🟠 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.

jlucaso1 commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed 2 of the 4 CodeRabbit findings in 9bbebe4:

  • Missing Arc import in the advanced/plugins.mdx stanza-interception example — fixed, added use std::sync::Arc;.
  • Undocumented MemoryReport field names (plugin_stanza_interceptors / plugin_core_event_subscriptions) referenced from advanced/plugins.mdx — added a plugin_stanza_interceptors row to the MemoryReport table in api/client.mdx, and dropped the unbacked mention of plugin_core_event_subscriptions (a pre-existing field that isn't documented anywhere in this repo yet — out of scope here).

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 (add_stanza_interceptor/acquire_decrypted_payload_forwarding in api/client.mdx, DecryptedPayload in concepts/events.mdx, "Stanza interception" in advanced/plugins.mdx) matches the established voice used throughout these same pages — e.g. the RawNode section right above the new DecryptedPayload one, and the rest of api/client.mdx. Rewriting just the new sections to second-person would make them inconsistent with their neighbors rather than more consistent. Also, the DecryptedPayload heading is already code-formatted (### `DecryptedPayload`) — that part of the finding doesn't match the current file.


Generated by Claude Code

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread api/client.mdx Outdated
Comment thread advanced/plugins.mdx Outdated
@greptile-apps

greptile-apps Bot commented Aug 8, 2026

Copy link
Copy Markdown

Greptile Summary

Documents the newly released stanza interception APIs, decrypted-payload forwarding event, and plugin interception capability.

  • Adds client API contracts, examples, acknowledgement behavior, and memory-report fields.
  • Documents decrypted payload event fields, emission paths, and lease-based forwarding.
  • Describes plugin capability registration, panic isolation, lifecycle invalidation, diagnostics, and Signal durability implications.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

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

Comment thread api/client.mdx Outdated

@cubic-dev-ai cubic-dev-ai 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.

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.

jlucaso1 commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

Fixed the remaining valid findings from Greptile and cubic in 2d10a46:

  • Undefined bot in the acquire_decrypted_payload_forwarding example (Greptile) — the lease was acquired from client but the handler was registered through an undeclared bot. Rewrote the example to use client.register_handler + ChannelEventHandler, the same self-contained pattern the register_handler section above it already uses.
  • Lease is necessary but not sufficient (cubic) — added a note that a handler with a narrowed interest() also needs EventKind::DecryptedPayload added back in, matching the caveat concepts/events.mdx already states for this event.
  • Undocumented wire-string capability names (cubic) — stanza.intercept and events.core.observe appeared in prose without ever being defined on the page; replaced both with the actual PluginCapability variant names the rest of the page uses.

Generated by Claude Code

@cubic-dev-ai cubic-dev-ai 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.

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

@jlucaso1
jlucaso1 merged commit 99587a9 into main Aug 8, 2026
4 checks passed
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.

2 participants