refactor(chat-actions)!: build message ranges from typed references
message_range now accepts typed MessageRef values with timestamps through IntoIterator, so callers no longer construct protobuf keys or an intermediate Vec. It projects each reference once with MessageRef::to_raw_key and retains timestamps, iteration order, and empty ranges.
Removes only the free message_key factory and its crate/features reexports. MessageContext::message_key, SendResult::message_key, MessageRef::to_raw_key, and the private action-index helper remain unchanged. No client or message body is retained, and no dependencies or parallel legacy API are added.
Breaking migration
// Before: message_range(last, system, vec![(target.to_raw_key(), timestamp)])
// After:
let range = whatsapp_rust::message_range(last, system, [(target, timestamp)]);
The exact item type is (MessageRef<'a>, i64). Pass an array, vector, or iterator; use target.clone() if the reference must be reused. Empty input can be []. Explicit protobuf interop uses MessageRef::to_raw_key or MessageKey directly. The free whatsapp_rust::message_key and whatsapp_rust::features::message_key imports are removed.
Validation
Regression fixtures cover PN/LID DMs, group authors including device suffixes, own messages with/without known author, timestamp extremes, order and empty ranges. The existing independent actions consumer checks detached ownership and retained accessors; compile-fail doctests reject both removed exports and the old raw-key range input.
Local validation passed on the pinned nightly: formatting, all 24 chat-action regression tests, 2 independent actions-consumer tests, 38 actions doctests, and the wasm32-unknown-unknown consumer check. Rust 1.94.1 also passed the 2 actions-consumer tests and 38 doctests. WASM emitted two existing unused-qualification warnings in untouched request.rs and upload.rs.
Greptile reviewed a9e5b053 with no findings (5/5 confidence). Cubic could not review because its monthly quota was exhausted. Before the ready transition, 36 checks passed, 2 were neutral and 2 skipped, with no running CI checks. The ready transition triggered reviews of the same a9e5b053 head. Codex code review completed at 15:33 UTC and security review at 15:37 UTC on 2026-10-05, with no published findings. CodeRabbit selected all five changed files but still reports pending / Review in progress; its review is not yet complete. This includes Build & Test, all-features tests/lint, clippy, rustdoc, the complete feature matrix, native/MSRV consumers, WASM, E2E, Miri and the binary-size gate.
Binary-size comparison: zero delta in stripped bytes (11,520,664), .text (9,290,358), and allocated sections (11,521,874). Library LLVM lines decreased by 709 and copies by 34; dependency count is unchanged. The first attempt failed to discover the existing exact-base artifact; a targeted job retry validated base bd1f3069 and passed. The canonical comparator also passed locally against those same official artifacts. The informational semver failure compares unchanged wacore, wacore-binary, and waproto against published 0.7.0; it is not a new failure caused by this SDK patch. Base: bd1f3069. Implements R05 from the authorized 2026-10-05 API report. External documentation migration is coordinated separately.
CodSpeed's neutral advisory reports ~8.2% regressions in bench_session_with_self[false/true] in wacore-libsignal and a ~13.3% improvement in bench_session_root_key_update. This patch does not change that crate, its benchmark source, the lockfile, or the proto-signal job; wacore-libsignal does not depend on the SDK changed here. The advisory has not been acknowledged or claimed resolved, and these observations do not establish its cause.