Skip to content

docs(signal-protocol): document DH ratchet lease rebase and session quarantine - #452

Merged
jlucaso1 merged 2 commits into
mainfrom
claude/nifty-bohr-gei9bi
Jul 27, 2026
Merged

docs(signal-protocol): document DH ratchet lease rebase and session quarantine#452
jlucaso1 merged 2 commits into
mainfrom
claude/nifty-bohr-gei9bi

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Documents whatsapp-rust#1149, "fix(signal): stop a DH ratchet stranding the counter lease".

What changed upstream

A DH ratchet replaces a session's sender chain in place (fresh key material, counter reset to zero) without archiving the retired chain. The record-level sender-chain counter lease wasn't rebased when this happened, so the ceiling could keep describing a chain that no longer existed. For a peer you mostly monologue at (e.g. your own other device, which receives a copy of every outgoing message but rarely replies), this could strand the ceiling thousands of counters above the live chain — and on the next restart/lossy cache reset, recovery would refuse to fast-forward past MAX_RESERVATION_FAST_FORWARD and fail to load the session record at all, permanently stranding that address (breaking decrypt, group-send fan-out, and retry-receipt handling for it).

The fix has two parts:

  1. SessionRecord::rebase_lease_after_sender_chain_reset() lowers the lease ceiling to at most one reservation batch as part of the same mutation that swaps in the fresh chain, preventing new occurrences.
  2. SignalStoreCache now reports an undecodable/corrupted session row as absent rather than surfacing a load error, letting the ordinary no-session recovery path replace it automatically. This self-heals rows that were already stranded by builds predating fix 1. A new wa_session_record_quarantined_total counter tracks this.

Doc changes

  • advanced/signal-protocol.mdx — new "DH ratchet resets rebase the lease" subsection under Flush scheduling, explaining the bug and the rebase fix, including MAX_RESERVATION_FAST_FORWARD (previously undocumented).
  • concepts/storage.mdx — new paragraph under SignalStoreCache documenting the undecodable-row quarantine behavior and the has_session() semantics change (it now decodes rather than only checking existence).
  • advanced/metrics.mdx — added wa_session_record_quarantined_total to the counters table.
  • api/signal.mdx — added a note to "Reset a broken session" clarifying that an undecodable row no longer needs manual delete_sessions/assert_sessions intervention.

No changelog entries were added, per standing instructions that changelog entries are human-authored only.


Generated by Claude Code


Summary by cubic

Document DH ratchet resets rebasing the sender-chain lease and the new quarantine behavior for undecodable session rows.
Adds the wa_session_record_quarantined_total metric, clarifies that SignalStoreCache treats undecodable rows as absent and that has_session decodes, notes that recovery happens on the next send or decrypt and overwrites the unreadable row, and scopes the “Reset a broken session” example to logically invalid sessions.

Written for commit 53598ea. Summary will update on new commits.

Summary by CodeRabbit

  • Documentation
    • Added metrics documentation for tracking session records that cannot be decoded.
    • Clarified how session storage handles undecodable records and supports automatic recovery.
    • Documented sender-chain resets, counter leases, recovery behavior, and stranded-session handling.
    • Updated the session reset example to explain when manual resets are required.

…uarantine (whatsapp-rust#1149)

Documents the counter-lease-stranding fix from whatsapp-rust PR #1149: a DH
ratchet now rebases the sender-chain lease onto the fresh chain instead of
leaving a stale ceiling that could refuse to load past
MAX_RESERVATION_FAST_FORWARD, and an undecodable session row is now
quarantined (reported absent) rather than propagated as a load error, so
recovery can replace it automatically. Also adds the new
wa_session_record_quarantined_total metric to the counter catalogue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ECfouxpzsKhJ4heK8MUDk
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The documentation describes undecodable session-row quarantine, its metric and self-healing recovery behavior, and how DH ratchet resets rebase sender-chain counter leases.

Changes

Session recovery documentation

Layer / File(s) Summary
Session-row quarantine contract
concepts/storage.mdx, advanced/metrics.mdx, api/signal.mdx
Documents undecodable rows as absent, records the quarantine metric, and clarifies when manual session reset is required.
Ratchet lease reset behavior
advanced/signal-protocol.mdx
Explains sender-chain lease rebasing during DH ratchet resets and recovery from stranded lease ceilings.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

Poem

A rabbit hops where session rows once froze,
Now absent rows can heal as recovery flows.
Leases rebase when ratchets turn anew,
Metrics count the quarantined few.
Squeak—clear docs make the path shine through!

🚥 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 main docs changes: DH ratchet lease rebasing and session quarantine.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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 27, 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 27, 2026, 5:43 PM

💡 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 `@api/signal.mdx`:
- Around line 628-630: Update the reset example near the Note to scope it to
sessions that decode successfully but are logically invalid, such as after an
identity compromise; remove or replace the “corrupted session” wording so
undecodable storage rows are not directed to manual reset.

In `@concepts/storage.mdx`:
- Line 350: Rewrite the quarantine explanation in concepts/storage.mdx lines
350-350 using active voice, concise sentences, and direct second-person phrasing
while preserving the existing behavior and details. Apply the same style to the
lease-reset explanation in advanced/signal-protocol.mdx lines 1303-1312: split
long sentences and address the reader directly; no code changes are required.
🪄 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: b928da98-5291-4d7c-a562-9a1d8291acf0

📥 Commits

Reviewing files that changed from the base of the PR and between 9f974f0 and 4f838ed.

📒 Files selected for processing (4)
  • advanced/metrics.mdx
  • advanced/signal-protocol.mdx
  • api/signal.mdx
  • concepts/storage.mdx

Comment thread api/signal.mdx Outdated
Comment thread concepts/storage.mdx Outdated

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

ℹ️ 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 api/signal.mdx Outdated
Comment thread concepts/storage.mdx Outdated
Comment thread concepts/storage.mdx Outdated
- Scope the "Reset a broken session" example to logically-invalid
  sessions instead of "corrupted" ones, since undecodable rows no
  longer need it (CodeRabbit).
- Correct the self-heal claim: a plain load only reports a row
  absent, it doesn't repair it — recovery happens on the next send
  or decrypt that establishes a replacement session (Codex).
- Note that recovery overwrites the unreadable row, which matters
  during a version rollback to a build that could still decode it
  (Codex).
- Split the dense quarantine paragraph into bullets and rewrite both
  new sections in active, second-person voice per AGENTS.md
  (CodeRabbit).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ECfouxpzsKhJ4heK8MUDk
@jlucaso1
jlucaso1 merged commit bc7325d into main Jul 27, 2026
3 checks passed

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

ℹ️ 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 concepts/storage.mdx

- `get_session`, `checkout_session`, and `has_session` all report that row as **absent** instead of propagating a decode error. Loading the row doesn't repair it by itself — it only lets the caller treat the address as session-less.
- That matters because the paths that would otherwise repair the session — decrypting the peer's next pre-key message, the retry-receipt handler — have to load the record first. If the decode error propagated instead, it would strand the address until you deleted the row by hand.
- Reporting the row absent lets the ordinary no-session recovery run instead: the next send or decrypt for that address fetches a fresh pre-key bundle and persists a replacement session, overwriting the unreadable row. This build never derives key material from bytes it can't decode, so it loses nothing usable — but the overwrite is destructive to the original bytes. If you're rolling back to a build that could still decode that row, back up the database first; the original bytes don't survive the overwrite.

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 Distinguish inbound retry recovery from bundle fetching

When the next use is an inbound ciphertext, decryption does not fetch a fresh peer pre-key bundle: an ordinary message without a usable session triggers a retry, and only a later pre-key message can establish the replacement session. The revised wording correctly says that loading alone does not repair the row, but this sentence still promises that the next decrypt both fetches a bundle and recovers automatically; distinguish the outbound send's server-side bundle fetch from the inbound retry/pre-key-message flow.

Useful? React with 👍 / 👎.

Comment thread advanced/metrics.mdx
| `wa_appstate_mutations_total` | — | App-state mutations applied |
| `wa_identity_change_total` | — | Peer identity changes that triggered a session reset |
| `wa_prekey_upload_total` | `outcome` = `ok`, `fail` | Pre-key uploads by outcome |
| `wa_session_record_quarantined_total` | — | Stored session rows that failed to decode and were treated as absent for recovery. Steady state is zero — see [session row quarantine](/concepts/storage#signalstorecache) |

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 counter's rate rather than its value

Because this is a monotonic _total counter, its value remains non-zero after the first quarantined row and does not return to zero during a healthy steady state. Saying that steady state is zero can lead operators to alert on the cumulative value and keep an alert firing indefinitely; document that the expected steady-state increase or rate is zero and that a positive rate is the signal to investigate.

Useful? React with 👍 / 👎.

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