Skip to content

feat(channels): carry the sender's display name; keep a LID sender a LID - #50

Merged
M3gA-Mind merged 1 commit into
tinyhumansai:mainfrom
M3gA-Mind:feat/channel-sender-name
Oct 8, 2026
Merged

M3gA-Mind merged 1 commit into
tinyhumansai:mainfrom
M3gA-Mind:feat/channel-sender-name

Conversation

@M3gA-Mind

Copy link
Copy Markdown
Collaborator

Summary

  • ChannelMessage gains sender_name: Option<String>: the sender's display name as the platform gives it. OpenHuman will store it as the name of the person a channel memory is about.
    • WhatsApp Web: the message's push name (info.push_name).
    • WhatsApp Cloud API: value.contacts[].profile.name of the contact whose wa_id is the message's from.
    • Telegram: first and last name, else the username (sender stays the username or id).
    • Signal: the envelope's sourceName.
    • Other providers: None. No channel exposes the user's saved contact name, so none is synthesised.
  • The envelope maps it to and from the existing SenderRef.name; both projections used to drop it.
  • ChannelMessage now derives Default, so callers can spread ..Default::default() and keep compiling when an optional field is added.
  • WhatsApp Web, LID senders. A sender addressed on the lid server (WhatsApp's privacy identifier) is now the phone that came with the message (sender_alt), else the LID JID itself (<lid>@lid). It used to be rendered as +<lid>.

API Or Behavior Changes

  • Public API (Rust): a new pub field on ChannelMessage, plus Default. Every struct literal of ChannelMessage without a .. spread must add sender_name: None (or switch to ..Default::default()). That's 27 literals in this repo, all updated, and about 44–46 in OpenHuman, to be done in the OpenHuman pin bump. RuntimeChannelMessage is unchanged, so OpenHuman's RuntimeChannelMessage { message, inbound_envelope } destructuring is unaffected.
  • Wire: sender_name is #[serde(default, skip_serializing_if = "Option::is_none")], and ChannelMessage has no deny_unknown_fields. A host or module built before this field decodes a newer message (the field is ignored), and a newer one decodes an older message (None). Test: the_sender_name_is_optional_on_the_wire.
  • Contract version is NOT bumped (stays 1). is_compatible is an exact match (crates/tinychannels-bus/src/version.rs), so a bump would stop every older host binding the new module, for a change that is wire-compatible both ways. Nothing in the module ↔ host binding forces the two to move together: tinychannels-module only imports is_compatible/CONTRACT_VERSION, and OpenHuman's module record pins a release, not a contract range. The source-linked crate and the lazily loaded module can therefore be bumped independently.
  • Behavior, WhatsApp Web LID senders (sender_identity in providers/whatsapp_web.rs):
    • Phone-addressed sender: unchanged, +<number>.
    • LID sender whose phone JID came with the message: sender and the DM reply target are +<phone>.
    • LID sender alone: sender and the DM reply target are <lid>@<server> (e.g. 98765432101234@lid), not +<lid>.
    • This changes the sender key for LID-only contacts. On the host, their channel thread / conversation history may not continue across the upgrade (they read as a new sender once).
    • Reply routing: a DM reply to a LID sender went to recipient_to_jid("+<lid>"), i.e. Jid::pn(<lid>), a phone JID made of the LID's digits that isn't this person. It now goes to the LID JID (or the real phone). That misrouting was inferred from the code (compute_reply_target, recipient_to_jid), not observed live.
    • Allow-list: allowed_numbers still matches the old +<lid> form, plus +<phone> when known, so existing configs keep matching. The outbound gate already normalises a <lid>@lid target to +<lid>.
    • Logs redact the sender with redact_recipient, which handles both forms.

Tests

Not run locally (team rule: CI runs every check; no local builds). cargo fmt --all was run. The CI here runs clippy, build and test both default and --all-features (the whatsapp-web feature included). M3gA-Mind fork PRs to this repo do get CI (e.g. #37).

New tests:

  • crates/tinychannels-bus/src/channel/mod_tests.rs: the_sender_name_survives_the_envelope_both_ways, the_sender_name_is_optional_on_the_wire.

  • src/providers/whatsapp_web_tests.rs: a_phone_addressed_sender_is_its_number, a_lid_sender_with_its_phone_is_the_phone, a_lid_sender_alone_stays_a_lid_jid_not_a_phone (the latter asserts the reply target parses to a LID-family JID).

  • src/providers/whatsapp_tests.rs: whatsapp_parse_takes_the_senders_profile_name, whatsapp_parse_without_contacts_has_no_name.

  • src/providers/telegram/channel_tests.rs: telegram_sender_name_is_first_and_last_name, telegram_sender_name_falls_back_to_username_then_none.

  • src/providers/signal_tests.rs: process_envelope_carries_the_profile_name, sse_envelope_reads_source_name.

  • cargo fmt --check (ran cargo fmt --all)

  • cargo clippy --all-targets -- -D warnings: CI

  • cargo clippy --all-targets --all-features -- -D warnings: CI

  • cargo build --all-targets: CI

  • cargo build --all-targets --all-features: CI

  • cargo test: CI

  • cargo test --all-features: CI

Documentation

The rustdoc on ChannelMessage.sender_name and WhatsAppWebChannel::sender_identity describes the fields and the LID rule. No spec under docs/ lists ChannelMessage fields, so none needed changing.

ChannelMessage gains sender_name: Option<String>, the name the platform
gives for the sender: the WhatsApp Web push name, the WhatsApp Cloud
contacts[].profile.name of the sender's wa_id, Telegram's first and last
name (else the username), and Signal's sourceName. Never a saved contact
name: no channel exposes one. It is serde-defaulted and skipped when
None, so hosts and modules built before it still decode each other's
messages; the wire contract version stays 1 (is_compatible is an exact
match, so a bump would stop old hosts binding the new module). The
envelope maps it to and from SenderRef.name, which both projections used
to drop. ChannelMessage now derives Default, so a caller can spread
..Default::default().

WhatsApp Web: a LID-addressed sender was rendered as +<lid>, which looks
like a phone number and, as a DM reply target, became a phone JID of the
LID's digits. It is now the phone that came with the message (sender_alt)
when there is one, else the LID JID itself (<lid>@lid). The allow-list
still accepts the old +<lid> form.
@tinysweeper

tinysweeper Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Tiny Sweeper reviewed this change across 6 lane(s) and found 0 active actionable finding(s). Detailed lane evidence and any incomplete work are listed below.

State: Ready for maintainer review
Priority: none
Reviewed head: d550f62ad0c2
Updated: 1791459890 (Unix time)

Review snapshot

Change surface Files Review signal Count
Production 18 Active findings 0
Tests 8 Noted findings 0
Documentation 0 Resolved findings 0
Configuration 0 Pending checks/questions 0

Completeness: Complete
Test assessment: No supported feature-to-test mapping was available; this does not mean tests are absent or passed.

What changed

The review could not produce a supported behavioral summary; inspect the cited changed surface and lane details below.

Features

None identified with supported citations.

Tests

No supported feature-to-test mapping was produced. Test execution is not inferred.

Findings

No active actionable findings.

Before merge

None.

How this fits together

flowchart LR
  n0["message<br/>changed"]:::changed
  n1["ChannelMessage<br/>changed"]:::changed
  n0 -->|uses| n1
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading
Agent review details

critique

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 26 files; 0 findings. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

security

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 26 files; 0 findings. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The change adds an optional `sender_name` to `ChannelMessage` (wire-optional via `#[serde(default, skip_serializing_if)]`), populates it in the Telegram, WhatsApp, WhatsApp Web and Signal providers, and reworks WhatsApp Web's sender identity for LID-addressed senders. Every behavioural change is exercised by a test that would fail on regression: the round-trip and wire-compat tests in `mod_tests.rs`, the trim/empty-filter tests for Signal, Telegram and WhatsApp, the LID identity tests including the `compute_reply_target`/`recipient_to_jid` reply path, and the allow-list form-matching intent pinned through `sender_identity`. The many `sender_name: None` literal insertions are mechanical updates forced by struct literals and cannot regress silently. I found no untested invariant or unexercised branch; the change looks safe to merge. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

commits

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: Nothing sensitive found in what this pull request commits.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The PR adds an optional `sender_name` to `ChannelMessage` (with `Default` and wire-compatible serde attrs), maps it through the envelope, and fills it from WhatsApp Web push names, Cloud API contacts, Telegram user names, and Signal `sourceName`, plus fixes WhatsApp Web LID sender identity. The diff matches the description in every particular, including the claimed tests, which are present and assert what the body says they do. Looks sound to merge once CI passes. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

e2e

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: No end-to-end harness in this repository: no e2e test files and no e2e workflow.
Evidence and run details
  • Models: gpt-5.6-luna, glm-5.3-flash
  • Spend: $0.066330
  • Tokens: 533034 input · 23595 output · 73722 cached · 0 embedding
Head State Pass summary
d550f62ad0c2 ready for maintainer review 0 active finding(s), 0 resolved finding(s) (at 1791459890)

tinysweeper 0.1.0

@coderabbitai

coderabbitai Bot commented Oct 8, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 54713c8d-f7f9-4180-82fb-7b7c7a4f63c6
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@tinysweeper tinysweeper 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.

tinysweeper found nothing blocking. Approving.

             $0.0663 · 533,034 in / 23,595 out · 73,722 cached (14%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0266 · 243,754 in / 10,461 out · 43,047 cached (18%) · gpt-5.6-luna
security:    $0.0393 · 251,457 in / 8,874 out  · 30,547 cached (12%) · gpt-5.6-luna
tests:       $0.0001 · 12,319 in  / 377 out    · 64 cached (1%)      · glm-5.3-flash
description: $0.0001 · 12,868 in  / 281 out    · 64 cached (0%)      · glm-5.3-flash

@tinysweeper tinysweeper Bot added the priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. label Oct 8, 2026
@M3gA-Mind
M3gA-Mind merged commit 73de620 into tinyhumansai:main Oct 8, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant