Skip to content

refactor(deps): drop redundant crates and unused dependency features - #1200

Merged
jlucaso1 merged 2 commits into
mainfrom
claude/audit-optimize-dependencies-uk195m
Jul 30, 2026
Merged

refactor(deps): drop redundant crates and unused dependency features#1200
jlucaso1 merged 2 commits into
mainfrom
claude/audit-optimize-dependencies-uk195m

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Audit of every direct dependency in the workspace, looking for crates whose job something already linked can do, plus features that are enabled but never reach any code. Nine crates leave the dependency graph (471 to 462 in Cargo.lock) and two enabled-but-unused features are dropped. Every removal is a substitution by something already in the tree; the breaking changes are listed explicitly below and are all in dead or unreferenced surface.

Audit

Crate Replaced by Where
typed-builder (+ typed-builder-macro) bon, already a hard dependency of wacore wacore/src/iq/groups.rs
flate2 (runtime) wacore_binary::zlib_pool::decompress_zlib_pooled, already zlib-rs wacore/src/voip/mlow/smpl_tables_blob.rs:35
bytemuck u16::from_le_bytes / to_le_bytes per lane wacore/appstate/src/lthash.rs:81
arrayref slice::split_first_chunk wacore/libsignal/src/protocol/ratchet/keys.rs
displaydoc thiserror, already derived on every one of those enums 5 files under wacore/libsignal/src
derive_more (+ derive_more-impl) hand-written From/Into/TryFrom 7 files under wacore/libsignal/src
uuid removed with the dead ServiceId types wacore/libsignal/src/core/address.rs
iana-time-zone (+ -haiku, android_system_properties) chrono now instead of clock root and storages/chat-store

Two notes on the interesting ones:

flate2. The only non-test call was inflate() for the MLow constant tables. wacore-binary already talks to zlib-rs directly through the pooled inflater, and wacore already depends on it, so the wrapper crate bought nothing. It stays as a dev-dependency because tests still need the compression side, which the pool does not expose.

bytemuck. The casts were transmutes between the byte array and the lane array, followed by a manual swap_bytes pass under cfg!(target_endian = "big"). from_le_bytes per lane says the same thing once, and on little-endian lowers to the load the transmute emitted.

Things checked and deliberately left alone:

  • x25519-dalek could be expressed on top of curve25519-dalek (already a direct dependency), but StaticSecret clamping and diffie_hellman are load-bearing crypto and the wrapper is thin. Not worth the risk for one crate.
  • scopeguard has no in-tree equivalent, so replacing it means copying it. Kept.
  • http in whatsapp-rust-tokio-transport looks removable, but ClientBuilder::add_header takes http::HeaderName and http::HeaderValue, and tokio-websockets does not re-export them.
  • buffa's json feature and serde's rc are both load-bearing: json supplies the Serialize impl for MessageField that the generated waproto code needs, rc supplies it for the Arc<str> fields in wacore/src/store/traits.rs. Both were verified by removing them and watching the build fail.
  • diesel's 32-column-tables is the smallest tier that fits; the widest table (device) has 27 columns.
  • tokio-websockets' rand picks the RNG backend; rand is the one already in the tree, so it is the right pick over fastrand/getrandom.
  • aws-lc-rs appears in Cargo.lock but cargo tree -i finds no path to it under any feature combination, so there is nothing to gate.
  • scheduled-thread-pool, stable_deref_trait, md5, smoothutf8, itoa, portable-atomic and hashbrown are each used directly for a reason that has no substitute in the tree.

Breaking changes

All four are in surface with no in-tree call site.

  1. wacore_libsignal no longer exports Aci, Pni, ServiceId, ServiceIdKind, ServiceIdFixedWidthBinaryBytes or WrongKindOfServiceIdError. These are Signal-app account identity with no WhatsApp meaning, and the only reason uuid was linked. Nothing to migrate: no call site existed.
  2. TryFrom for CiphertextMessageType and IdentityChange now fails with wacore_libsignal::core::UnknownDiscriminant<T> instead of derive_more::TryFromReprError<T>. Migration: match on UnknownDiscriminant { value }. The input types are unchanged (u8 and isize respectively, the latter being what #[try_from(repr)] fell back to under repr(C)).
  3. chrono::Local is no longer reachable through the whatsapp_rust::chrono re-export, since Local is gated behind chrono's clock. Deliberate: Local never appears in this crate's API, the re-export exists so consumers can name the types that do, and clock costs three crates plus a per-OS timezone backend. Migration: depend on chrono directly with clock.
  4. GroupCreateOptionsBuilder::build and GroupParticipantOptionsBuilder::build are hand-written rather than derived, preserving the generic build<T: From<Options>>() -> T shape that typed-builder's build_method(into) produced. bon's own finisher is finish(). No source change should be needed on either side, and cargo-semver-checks confirms it: wacore is in the checked set and comes back clean.

Changes

  • wacore: GroupCreateOptions and GroupParticipantOptions build with bon::Builder. bon spells a non-None default only on a member marked required, so the four fields defaulting to a present value carry required plus a with closure that restores the bare-value setter. Setter shapes and build()'s signature are unchanged.
  • wacore: MLow table blobs inflate through wacore-binary's pooled inflater, with a 4 MiB cap (the largest committed blob is 30 KB compressed).
  • wacore-appstate: the SIMD ltHash lane conversion is explicit little-endian, dropping the endianness branch along with bytemuck.
  • wacore-libsignal: displaydoc doc comments became #[error(...)] attributes with the same format strings; CurveError derives thiserror::Error instead of hand-implementing std::error::Error. IdentityChange keeps #[repr(C)], so its C layout guarantee is untouched.
  • chrono moves from clock to now in the root package and chat-store.
  • hashbrown's equivalent and aes-gcm's bytes features are dropped. Verified against the resolved graph, not just the manifest: cargo tree -f "{p} | {f}" now shows hashbrown v0.17.1 with no features and aes-gcm v0.11.0 with only aes,alloc.
  • Manifest hygiene: three dev-dependency entries that restated a normal dependency verbatim (root async-trait, sqlite-storage tokio, wacore-noise waproto) are removed, and waproto's dev serde_json now uses the workspace pin instead of a loose "1".

Cost

Nine crates out of Cargo.lock, and the binary gets slightly smaller: -1.56 KiB stripped (-0.02%), -1.44 KiB .text, -3.99 KiB allocated, with llvm-lines flat in both wacore and the root lib. The real win is compile time and supply-chain surface rather than bytes, since four of the nine were proc macros and flate2 was a wrapper over zlib-rs that was already linked.

The per-crate attribution in the size report reads oddly (whatsapp_rust +4.94 KiB against other deps -5.75 KiB) and should not be read as this PR adding code to the root crate: no file under src/ changed. That is cargo-bloat re-attributing inlined code to the caller once the crate it came from is gone, which is also why metrics_exporter_prometheus, a dev-dependency that never linked into this binary, shows up as "removed".

On the hot paths nothing gains work: the bytemuck and arrayref replacements are the same machine code on little-endian, and the ltHash change removes a branch.

Validation

cargo fmt --all
cargo test --workspace --exclude whatsapp-rust-voip-cli --exclude e2e-tests --exclude bench-integration
cargo check --workspace --all-targets --all-features --exclude whatsapp-rust-voip-cli

All green: 3200+ tests across the workspace, plus doctests. whatsapp-rust-voip-cli is excluded because its cpal to alsa-sys chain needs ALSA headers this environment does not have; it was not touched. Full matrix left to CI.

Semver Checks (informational) is red, and it is red on the base branch too: the same job fails at 309e95d, main's tip when this branch was cut (run 30576243450, step "Check API against the last published release"). The workflow reports green there only because the job is continue-on-error. All 63 flagged items are waproto::whatsapp::* generated protobuf types drifting from the published 0.6.0 baseline; this PR touches no .proto file and no generated code, only waproto/Cargo.toml's dev-dependency line. Zero findings name wacore or wacore-binary, the other two crates in the checked set.

Nine crates leave the dependency graph, each replaced by something the
workspace already links or by plain core:

- typed-builder: bon is already a hard dependency of wacore and covers the
  one struct pair that used it (wacore/src/iq/groups.rs).
- flate2: the only runtime use was inflating the MLow table blobs, which
  wacore-binary's pooled zlib-rs inflater already does. It stays as a
  dev-dependency for the compression side of tests.
- bytemuck: the three casts in lthash were transmutes between [u8; 16] and
  [u16; 8] wrapped in a manual big-endian swap. from_le_bytes per lane states
  the wire endianness once and drops both.
- arrayref: split_first_chunk carries the window length in the type.
- displaydoc: thiserror was already derived alongside it on every enum, and
  #[error(...)] is the same format string.
- derive_more: the From/Into/TryFrom derives covered newtypes and two repr
  enums; the hand-written impls are shorter than the attributes were.
- uuid: only reachable through Aci/Pni/ServiceId, which are Signal-app
  identity types with no WhatsApp meaning and no use anywhere in the tree.
- iana-time-zone and its two platform backends: chrono's `clock` feature
  exists to resolve the local timezone, and only Utc is ever used.

Feature trims that keep the same crates but compile less of them:
hashbrown's `equivalent` and aes-gcm's `bytes` were both enabled and unused.

Also removes three dev-dependency entries that restated a normal dependency
verbatim, and points waproto's dev serde_json at the workspace pin.

BREAKING CHANGE: wacore_libsignal no longer exports Aci, Pni, ServiceId,
ServiceIdKind, ServiceIdFixedWidthBinaryBytes or WrongKindOfServiceIdError.
The repr-based TryFrom impls on CiphertextMessageType and IdentityChange now
fail with wacore_libsignal::core::UnknownDiscriminant instead of
derive_more::TryFromReprError.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 28c66b3f-94ac-4c8a-b034-25b63fc44010

📥 Commits

Reviewing files that changed from the base of the PR and between 50dbe13 and 79c680b.

📒 Files selected for processing (4)
  • wacore/libsignal/src/core/mod.rs
  • wacore/libsignal/src/protocol/protocol.rs
  • wacore/libsignal/src/protocol/storage/traits.rs
  • wacore/src/iq/groups.rs

📝 Walkthrough

Summary by CodeRabbit

  • Improvements

    • More consistent cryptographic byte-order handling across platforms.
    • Compressed table loading now uses pooled decompression with a maximum size limit to improve decoding safety.
    • Encryption/decryption and protocol error messages are standardized for clearer output.
  • API Updates

    • Simplified public protocol address/identifier exports by removing legacy service-address identifier variants.
    • Identifier/discriminant conversions now use explicit unknown-mapping errors when values don’t match expected cases.
    • Group option builders were modernized for cleaner defaults and value assignment.

Walkthrough

The PR narrows dependencies, replaces generated Rust implementations, removes service identifier APIs, changes libsignal error formatting, updates byte and decompression paths, replaces ratchet slicing macros, and migrates group option builders to bon.

Changes

Workspace and library cleanup

Layer / File(s) Summary
Dependency manifest cleanup
Cargo.toml, storages/..., wacore/**/Cargo.toml, waproto/Cargo.toml
Dependency features and entries are removed or narrowed across workspace and crate manifests.
Runtime byte and decompression paths
wacore/appstate/src/lthash.rs, wacore/src/voip/mlow/smpl_tables_blob.rs
SIMD lane conversion uses explicit little-endian handling, and table inflation uses pooled zlib decompression with a size cap.
Public identifiers and conversions
wacore/libsignal/src/core/*, wacore/libsignal/src/protocol/*
Service identifier exports are removed, explicit conversions are added, and discriminant conversions return UnknownDiscriminant.
Explicit libsignal error formatting
wacore/libsignal/src/core/curve.rs, wacore/libsignal/src/crypto/*, wacore/libsignal/src/protocol/error.rs
Error enums move from displaydoc-derived formatting to explicit thiserror messages.
Ratchet key material slicing
wacore/libsignal/src/protocol/ratchet/keys.rs
HKDF output extraction replaces arrayref macros with split_first_chunk and range-based test comparisons.
Group option builders
wacore/src/iq/groups.rs
Group option builders migrate from TypedBuilder to bon::Builder, including optional defaults and setters.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: breaking-change

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 78.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title accurately summarizes the dependency cleanup and feature removal in this PR.
Description check ✅ Passed The description matches the changeset and covers the dependency audit, removals, and breaking API changes.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/audit-optimize-dependencies-uk195m

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.

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

ℹ️ 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 wacore/src/iq/groups.rs
Comment thread Cargo.toml
Comment thread wacore/libsignal/src/protocol/storage/traits.rs
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

📦 Binary size report

Metric main PR Δ
bin size (stripped) 9.95 MiB 9.95 MiB -1.56 KiB (-0.02%) 🔽
bin .text 7.97 MiB 7.97 MiB -1.44 KiB (-0.02%) 🔽
bin allocated (text+data+bss) 9.95 MiB 9.95 MiB -3.99 KiB (-0.04%) 🔽
llvm-lines wacore 511,608 511,608 0
llvm-lines wacore copies 16,704 16,704 0
llvm-lines whatsapp-rust lib 727,450 727,450 0
llvm-lines whatsapp-rust lib copies 22,955 22,955 0
deps crates (Cargo.lock) 471 462 -9 (-1.91%) 🎉
.text per crate
Crate main PR Δ
.text whatsapp_rust 1.80 MiB 1.80 MiB +4.94 KiB (+0.27%) 🔺
.text wacore 687.54 KiB 687.33 KiB -216 B (-0.03%) 🔽
.text wacore_binary 91.88 KiB 91.42 KiB -470 B (-0.50%) 🔽
.text wacore_libsignal 170.81 KiB 170.74 KiB -76 B (-0.04%) 🔽
.text wacore_appstate 22.35 KiB 22.35 KiB 0
.text wacore_noise 21.79 KiB 21.79 KiB 0
.text waproto 1.74 MiB 1.74 MiB 0
.text whatsapp_rust_sqlite_storage 515.96 KiB 515.96 KiB 0
.text whatsapp_rust_tokio_transport 40.49 KiB 40.49 KiB 0
.text whatsapp_rust_ureq_http_client 11.83 KiB 11.83 KiB 0
.text std 984.84 KiB 984.91 KiB +71 B (+0.01%) 🔺
.text other deps 1.91 MiB 1.90 MiB -5.75 KiB (-0.29%) 🔽
Top movers (cargo-bloat attribution)
Crate main PR Δ
metrics_exporter_prometheus 4.96 KiB (removed) -4.96 KiB (-100.00%)
whatsapp_rust 1.80 MiB 1.80 MiB +4.94 KiB (+0.27%)

Baseline: 309e95d70 (latest main run) · Head: 9f6b2a66c · Graphs

Three shapes changed by accident in the previous commit rather than by
decision:

- typed-builder's build_method(into) made build() finish into anything the
  options convert into. bon's finisher is renamed to finish() and build() is
  hand-written generic over From, so a downstream impl From<GroupCreateOptions>
  for its own request type still compiles. The reflexive From covers the
  plain case.
- IdentityChange is repr(C) again. Its layout is a public guarantee for FFI,
  and the hand-written conversion never needed the repr narrowed to u8.
- Because repr(C) leaves the discriminant type unspecified, IdentityChange's
  TryFrom takes isize, matching what the repr-driven derive fell back to.
  UnknownDiscriminant is generic over the discriminant type to carry both it
  and CiphertextMessageType's u8.

Copy link
Copy Markdown
Collaborator Author

Semver Checks (informational) is red here, and it is red on the base branch too, so it is not this PR's. The same job fails at 309e95d, main's tip when this branch was cut: run 30576243450, step "Check API against the last published release". The workflow shows green on main only because the job is continue-on-error.

All 63 flagged items are waproto::whatsapp::* generated protobuf types drifting from the published 0.6.0 baseline. This PR touches no .proto file and no generated code, only one dev-dependency line in waproto/Cargo.toml. Zero findings name wacore or wacore-binary, the other two crates the job checks, which is also the evidence that the bon builder swap did not change GroupCreateOptions' public shape. wacore-libsignal is not in the checked set at all, so the two intentional breaks there are documented in the PR body rather than caught here.

Everything else is green: clippy, rustdoc, fmt, cargo-deny, all four Miri jobs, wasm32 release, E2E, and the CodSpeed suites.


Generated by Claude Code

@codspeed-hq

codspeed-hq Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will degrade performance by 7.2%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 215 untouched benchmarks
⏩ 2 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation bench_reject_prekey_as_signal 1.1 µs 1.2 µs -7.2%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing claude/audit-optimize-dependencies-uk195m (79c680b) with main (309e95d)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@jlucaso1

Copy link
Copy Markdown
Collaborator Author

@codspeedbot why this is slower?

@codspeed-hq

codspeed-hq Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

@codspeedbot why this is slower?

Short answer: it isn't. The two revisions produce identical measurements when they run on the same machine — the 7.2% is the reported comparison crossing two different CI runners on a benchmark whose entire cost is 39 cache lines.

What the numbers actually say

bench_reject_prekey_as_signal measures a fast-fail parse. Its simulated cost breaks down as:

Component BASE (309e95d) HEAD (9f6b2a6)
instructions 78.3 ns (6.4%) 78.3 ns (6.4%)
caches 50.0 ns (4.4%) 54.2 ns (4.5%)
memory 1000.0 ns (89.1%) 1083.3 ns (89.1%)
total 1.128 µs 1.216 µs

The instruction term is bit-identical. Everything that moved is the cache/memory model, which is 93% of this benchmark's reported cost. In raw terms the whole delta is 3 last-level cache lines (36 → 39). One line is ~2.4% of this benchmark, so 3 lines is 7.2%.

Controlled A/B

I built and ran both revisions locally on one machine, same toolchain, same simulation instrument, and pulled the raw callgrind totals for this benchmark:

Ir + Dr + Dw LL misses derived cost
base 309e95d 282 39 1.216 µs
head 79c680b 282 39 1.216 µs

Identical. Not "within noise" — the same numbers. The miss split shuffles cosmetically (base 20 I1 / 8 D1r / 11 D1w, head 21 / 6 / 12) because inlining is re-attributed once the dependency set changes, but the sum is unchanged. The head figure also reproduces CI's head exactly (Ir 174, Dr 50, Dw 58, 39 misses → 1.2158 µs, matching the reported value to the digit), so the local run is measuring the same thing CI did.

I ran the whole libsignal suite the same way while I was there. All 21 benchmarks land within ±0.25% between base and head:

bench_dm_decrypt_subsequent_message      -0.24%
bench_dm_encrypt_first_message           -0.20%
bench_group_encrypt_message              -0.19%
bench_process_sender_key_distribution     0.12%
bench_reject_prekey_as_signal             0.00%   <- the flagged one
...all others |Δ| < 0.1%

Where the CI delta came from

The base run executed on an AMD EPYC 7763, the head run on an AMD EPYC 9V74. Simulation derives its cache model from the host CPU, so a benchmark costing 39 cold lines can move by a few lines on identical code — CodSpeed flags this benchmark explicitly under "Different runtime environments detected" in the report. Corroborating that: the first commit on this branch (50dbe13), which carries all the wacore-libsignal source changes including protocol.rs, measured exactly the base value (1.1283 µs, identical breakdown) on an Intel Xeon runner. The commit that shows the +7.2% only renamed the bon finisher, restored #[repr(C)] on IdentityChange, and made UnknownDiscriminant generic — none of which is reachable from SignalMessage::try_from.

Recommendation

Acknowledge it. Nothing in the diff touches this path, and the local A/B shows the code is neutral.

If you want it to stop flapping: the benchmark body is 174 instructions and ~89% of its reported cost is the cold-cache model, so its resolution is ~2.4% per cache line and it will keep moving whenever the binary is relinked or the runner changes. Looping the parse a few dozen times inside bench_refs would amortise the cold-fetch cost and give it a stable, instruction-dominated signal. Happy to push that if you'd like it — say the word and I'll open it as a separate change rather than folding a benchmark edit into a dependency PR.

Summary
  • Warming up the performance wizard...
  • Investigating the reported regression — Reproduced base and head on one machine: identical instruction and cache-miss counts. The 7.2% is runner-side cache-model variance, not a code change. No commit needed.
  • Handling comment — Comment handling finished successfully

Was this response helpful? React with 👍 or 👎 to help us improve CodSpeedBot.

Copy link
Copy Markdown
Collaborator Author

Pulled the raw instrument breakdown for bench_reject_prekey_as_signal from both runs. The answer is in the components, not the total:

Component BASE 309e95d HEAD 79c680b Δ
instructions 7.83333e-8 7.83333e-8 0
cache miss 5.00000e-8 5.41667e-8 ×1.0833
memory access 1.00000e-6 1.08333e-6 ×1.0833
cpu total 1.12833e-6 1.21583e-6 +7.2%

The instruction count is identical. Not close, identical. The executed instruction stream for this benchmark did not change, which rules out a code-path change: cpu total is the sum of the three rows, so the whole 7.2% comes from the two rows the simulator derives from the CPU's cache model.

And those two rows moved by exactly the same factor, 13/12, to the digit. A real regression moves memory accesses and cache misses independently, because it changes what the code touches. A uniform scale factor on both is a change in the model's cost weights, and CodSpeed's own comparison says why: the base ran on an AMD EPYC 7763 and the head on an AMD EPYC 9V74. It lists this benchmark explicitly under that hardware difference, with the note that Simulation mode "estimates CPU cycles by running the compiled code on a simulated CPU whose cache model is derived from the physical CPU."

Corroborating: all 216 benchmarks crossed the same runner change and 215 came back unchanged. This one surfaced because at ~1.1 µs it is among the smallest in the suite, so a fixed relative shift in the memory-cost weight clears the threshold here and nowhere else.

For completeness, the reject path is parse_signal_message! (length check, version check, protobuf view decode) and none of it is code this PR touched. The benchmark asserts is_err() and drops, so it never formats an error, which is where the displaydoc to thiserror swap lives.

No action taken. Happy to acknowledge it on CodSpeed if you'd rather clear the warning.


Generated by Claude Code

@jlucaso1
jlucaso1 merged commit 4c24b01 into main Jul 30, 2026
27 of 29 checks passed
@jlucaso1
jlucaso1 deleted the claude/audit-optimize-dependencies-uk195m branch July 30, 2026 21:29

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
wacore/appstate/src/lthash.rs (1)

81-101: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the SIMD test use an independent little-endian oracle.

Lines 181-187 call perform_pointwise_with_overflow twice, so a simd build executes the SIMD implementation for both values. Use asymmetric lane bytes and compute expected wrapping results directly from u16::from_le_bytes/to_le_bytes; this will catch the endian regression this change addresses.

🤖 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 `@wacore/appstate/src/lthash.rs` around lines 81 - 101, Update the SIMD test
around the two perform_pointwise_with_overflow calls so it uses asymmetric lane
bytes and an independent little-endian oracle rather than invoking the SIMD
implementation for both expected values. Compute each expected lane with
u16::from_le_bytes, apply the required wrapping operation, convert with
to_le_bytes, and compare the implementation result against those independently
derived bytes.
🤖 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 `@wacore/libsignal/src/protocol/storage/traits.rs`:
- Around line 30-49: Assign explicit numeric discriminants to both
IdentityChange variants, setting NewOrUnchanged to 0 and ReplacedExisting to 1.
Keep the existing TryFrom<u8> mapping unchanged and follow the
explicit-discriminant style used by CiphertextMessageType.

---

Outside diff comments:
In `@wacore/appstate/src/lthash.rs`:
- Around line 81-101: Update the SIMD test around the two
perform_pointwise_with_overflow calls so it uses asymmetric lane bytes and an
independent little-endian oracle rather than invoking the SIMD implementation
for both expected values. Compute each expected lane with u16::from_le_bytes,
apply the required wrapping operation, convert with to_le_bytes, and compare the
implementation result against those independently derived bytes.
🪄 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: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 28c66b3f-94ac-4c8a-b034-25b63fc44010

📥 Commits

Reviewing files that changed from the base of the PR and between 309e95d and 50dbe13.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (25)
  • Cargo.toml
  • storages/chat-store/Cargo.toml
  • storages/sqlite-storage/Cargo.toml
  • wacore/Cargo.toml
  • wacore/appstate/Cargo.toml
  • wacore/appstate/src/lthash.rs
  • wacore/libsignal/Cargo.toml
  • wacore/libsignal/src/core/address.rs
  • wacore/libsignal/src/core/curve.rs
  • wacore/libsignal/src/core/mod.rs
  • wacore/libsignal/src/crypto/aes_cbc.rs
  • wacore/libsignal/src/crypto/error.rs
  • wacore/libsignal/src/crypto/provider.rs
  • wacore/libsignal/src/protocol/error.rs
  • wacore/libsignal/src/protocol/identity_key.rs
  • wacore/libsignal/src/protocol/mod.rs
  • wacore/libsignal/src/protocol/protocol.rs
  • wacore/libsignal/src/protocol/ratchet/keys.rs
  • wacore/libsignal/src/protocol/state/prekey.rs
  • wacore/libsignal/src/protocol/state/signed_prekey.rs
  • wacore/libsignal/src/protocol/storage/traits.rs
  • wacore/noise/Cargo.toml
  • wacore/src/iq/groups.rs
  • wacore/src/voip/mlow/smpl_tables_blob.rs
  • waproto/Cargo.toml
💤 Files with no reviewable changes (4)
  • wacore/appstate/Cargo.toml
  • storages/sqlite-storage/Cargo.toml
  • wacore/noise/Cargo.toml
  • wacore/libsignal/Cargo.toml

Comment on lines +30 to +49
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum IdentityChange {
/// The protocol address didn't have an identity key or had the same key.
NewOrUnchanged,
/// The new identity key replaced a different key for the protocol address.
ReplacedExisting,
}

impl TryFrom<u8> for IdentityChange {
type Error = crate::core::UnknownDiscriminant;

fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
match value {
0 => Ok(Self::NewOrUnchanged),
1 => Ok(Self::ReplacedExisting),
_ => Err(crate::core::UnknownDiscriminant { value }),
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Pin the discriminants explicitly on IdentityChange.

Correct today because Rust defaults the first variant to 0, but the mapping is implicit — nothing stops a future edit from reordering/inserting a variant and silently breaking the hand-written TryFrom<u8> byte mapping. CiphertextMessageType right next door does this correctly with explicit values; let's be consistent and safe here too. I don't want silent protocol drift on my watch.

🔧 Proposed fix
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 #[repr(u8)]
 pub enum IdentityChange {
     /// The protocol address didn't have an identity key or had the same key.
-    NewOrUnchanged,
+    NewOrUnchanged = 0,
     /// The new identity key replaced a different key for the protocol address.
-    ReplacedExisting,
+    ReplacedExisting = 1,
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum IdentityChange {
/// The protocol address didn't have an identity key or had the same key.
NewOrUnchanged,
/// The new identity key replaced a different key for the protocol address.
ReplacedExisting,
}
impl TryFrom<u8> for IdentityChange {
type Error = crate::core::UnknownDiscriminant;
fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
match value {
0 => Ok(Self::NewOrUnchanged),
1 => Ok(Self::ReplacedExisting),
_ => Err(crate::core::UnknownDiscriminant { value }),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum IdentityChange {
/// The protocol address didn't have an identity key or had the same key.
NewOrUnchanged = 0,
/// The new identity key replaced a different key for the protocol address.
ReplacedExisting = 1,
}
impl TryFrom<u8> for IdentityChange {
type Error = crate::core::UnknownDiscriminant;
fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
match value {
0 => Ok(Self::NewOrUnchanged),
1 => Ok(Self::ReplacedExisting),
_ => Err(crate::core::UnknownDiscriminant { value }),
}
}
}
🤖 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 `@wacore/libsignal/src/protocol/storage/traits.rs` around lines 30 - 49, Assign
explicit numeric discriminants to both IdentityChange variants, setting
NewOrUnchanged to 0 and ReplacedExisting to 1. Keep the existing TryFrom<u8>
mapping unchanged and follow the explicit-discriminant style used by
CiphertextMessageType.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants