Skip to content

fix(chat-store): materialize deliberately shared group history - #246

Merged
jlucaso1 merged 1 commit into
mainfrom
fix/245-shared-group-history
Oct 23, 2026
Merged

jlucaso1 merged 1 commit into
mainfrom
fix/245-shared-group-history

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Received pairwise messageHistoryBundle attachments became unknown timeline rows, and their shared messages were never imported.

Persist eligible attachments inside the inbound durability transaction and consume them through a serial, bounded session downloader. Apply supported primary history messages with stale-copy semantics, translate sender keys from the sharing account's perspective, retain idempotency across restart, and keep imported history out of unread recounts. Classify visible notices as system lines, repair legacy carrier rows, and recover a revoke placeholder's original position without restoring deleted content.

Protocol evidence, bundle hashes, module offsets and limitations are recorded in the investigation. All 579 bundles from whatspec 46f6304, schema 4.4.0 / Web 2.3000.1047483476, were verified against the same commit's lock. Current engine and bridge source do not provide receiver materialization.

Validation:

  • Formatting and warnings-denied Clippy passed for both changed crates and all targets/features.
  • Nextest: 672 passed, 2 skipped. Doctests completed without failures.
  • The identical final regression file fails both tests on base 0ba4118 and passes here.
  • Synthetic fixtures cover durability, complete database reopening, duplicate/reordered copies, identity, malformed/partial bodies, notices/unread pagination and revokes. An earlier concurrent Cargo test run exhausted an existing opening poll budget; that test passed in both complete Nextest runs.

No authenticated reproduction was performed. This imports supported primary GroupHistory.messages; reporting-token, add-on and out-of-window-pin parity remain outside this correction. Only explicitly shared attachments are downloaded.

Hosted CI on 3ba4446 passed: CI ran 2,063 native tests with 13 skips; release artifacts built all four platforms and verified the downloaded archives; Pages built successfully with Publish skipped for this draft. Native Nextest reported one leaky existing daemon launcher fixture, which passed and is untouched here.

Closes #245.


Summary by cubic

Received messageHistoryBundle attachments now materialize shared group history instead of surfacing as unknown timeline rows whose messages were never imported.

  • Persists eligible attachments inside the inbound durability transaction and consumes them through a serial, bounded session downloader.
  • Applies supported history messages with stale-copy semantics, translating sender keys from the sharing account's perspective.
  • Keeps imported history out of unread recounts and renders visible notices as system lines.
  • Repairs legacy carrier rows and recovers a revoke placeholder's original timestamp and kind without restoring deleted content.

Closes #245.

Written for commit 3ba4446. Summary will update on new commits.

View guided diff Turn on auto-fix

Summary by CodeRabbit

  • New Features
    • Shared group-chat history can now be received and added to the conversation, including while the app retries temporarily unavailable history.
    • History notices appear as system messages when they contain visible information.
  • Bug Fixes
    • Imported history no longer increases unread counts or marks older messages as newly received.
    • Messages that only carry history data no longer appear as unknown items in the conversation.

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 782d2096-0200-4a48-9851-a44da0092d21
📥 Commits

Reviewing files that changed from the base of the PR and between 0ba4118 and 3ba4446.

📒 Files selected for processing: 23
  • crates/chat-store/migrations/2026-10-22-100000_shared_group_history/down.sql
  • crates/chat-store/migrations/2026-10-22-100000_shared_group_history/up.sql
  • crates/chat-store/src/error.rs
  • crates/chat-store/src/lib.rs
  • crates/chat-store/src/materialize.rs
  • crates/chat-store/src/queries.rs
  • crates/chat-store/src/schema.rs
  • crates/chat-store/src/store/history_sync.rs
  • crates/chat-store/src/store/inbound.rs
  • crates/chat-store/src/store/message_identity.rs
  • crates/chat-store/src/store/message_rows.rs
  • crates/chat-store/src/store/mod.rs
  • crates/chat-store/src/store/read_state.rs
  • crates/chat-store/src/store/shared_history.rs
  • crates/chat-store/src/store/writer.rs
  • crates/chat-store/src/types.rs
  • crates/chat-store/tests/regression_245.rs
  • crates/chat-store/tests/shared_history.rs
  • crates/session/src/whatsapp/convert.rs
  • crates/session/src/whatsapp/mod.rs
  • crates/session/src/whatsapp/shared_history.rs
  • crates/session/src/whatsapp/tests.rs
  • docs/shared-group-history.md
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@jlucaso1
jlucaso1 marked this pull request as ready for review October 23, 2026 00:36
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T00:40:04.738451Z 3ba4446 Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

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

ℹ️ 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 on lines +278 to +281
&message,
cs,
&mut quotes,
true,

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 Keep shared edit and revoke placeholders out of unread counts

When a bundle contains an edit or revoke whose target is not already stored, apply_history_message calls apply_edit or apply_revoke, which inserts a placeholder and increments the chat's unread count for incoming authors. The new shared flag only marks rows in the MessageOp::Store branch, so these placeholders also retain received_as_shared_history = false and remain eligible for later unread recounts. Consequently, importing old shared history can create unread badges and unread timeline entries despite the final zero-delta chat bump. Propagate the shared-history origin into these insertion paths and suppress their unread contribution.

Useful? React with 👍 / 👎.

Comment on lines +210 to +213
let author = stored_sender(author, false);
key.from_me = Some(own.contains(&author));
key.participant = Some(author.clone());
message.participant = Some(author);

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 Translate or remove aggregated reaction keys before importing

For a shared primary message carrying WebMessageInfo.reactions, only the outer message key and protocol target key are translated; the aggregated reaction keys retain the sharing account's perspective. apply_history_message nevertheless imports every aggregated reaction and interprets a reaction key with from_me = true as the local account's empty sender sentinel. This stores the sharing account's reactions under the wrong identity and prevents subsequent reactions or removals from that account from replacing them. Translate these nested keys before forwarding the message, or clear the reactions if add-on import is intentionally unsupported.

Useful? React with 👍 / 👎.

Comment on lines +166 to +169
let changed = diesel::sql_query("UPDATE shared_group_history SET completed = TRUE, proto = X'' WHERE device_id = ? AND chat_jid = ? AND msg_id = ? AND sender_jid = ? AND proto = ? AND timestamp_ms = ? AND completed = FALSE")
.bind::<Integer,_>(device).bind::<Text,_>(&bundle.chat_jid).bind::<Text,_>(&bundle.msg_id).bind::<Text,_>(&bundle.sender_jid).bind::<Binary,_>(&bundle.proto).bind::<BigInt,_>(bundle.timestamp_ms).execute(conn)?;
if changed == 0 {
return Ok(());

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 Retire pending history when its chat is cleared or deleted

If a clear/delete-chat update is applied after a bundle is persisted but before its download completes, the attachment remains pending: DeleteChatUpdate and ClearChatUpdate call delete_chat_rows, which removes messages and their reactions/receipts but never retires shared_group_history entries. Repository-wide searches for the new table and discard API confirm there is no deletion integration elsewhere. This completion check therefore still accepts the attachment, imports the old messages, and even recreates a deleted chat through bump_chat. Retire pending attachments covered by the clear/delete action in the same transaction, retaining their deduplication records so redelivery cannot restore the cleared history.

Useful? React with 👍 / 👎.

@jlucaso1
jlucaso1 merged commit 5ee0050 into main Oct 23, 2026
17 of 18 checks passed
@jlucaso1
jlucaso1 deleted the fix/245-shared-group-history branch October 23, 2026 00:45
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.

chat-store: a received group-history bundle is stored as an unknown message and the messages it shares are never materialized

1 participant