CRM resolver must never attribute messages to self
Building a personal CRM that ingests messages from many platforms (email, WhatsApp, iMessage) and routes each message to the right contact in a unified per-person timeline.
A symmetric (from, to) person-link resolver in a CRM is a self-attribution trap. The user's own person record typically carries their own contact identifiers (phone, email, LID) for back-reference and display. When the user sends a message, the from identifier matches the user's links. When they receive a group message, their identifier appears in to. Either way, a naive resolver that looks up matches across both sides will sometimes pick the user themselves as the message's subject, polluting the user's own timeline with messages where they are the SENDER not the topic. In production this resulted in 171 outbound WhatsApp messages being attributed back to the user's own person page over a few months. The principle: a message can never be ABOUT the user themselves; for inbound mail it belongs to the sender, for outbound mail it belongs to the recipient. Implement this by tagging one person record as me and excluding that record from the candidate match set at resolver time. The bug compounds with matrix bridge puppet MXIDs: mautrix-whatsapp generates outbound matrix events where sender is a puppet MXID like @whatsapp_15551234567:server rather than the user's real MXID, so a naive direction check sees not-our-mxid and sets direction=in even though it is the user's own outbound message. Fix both: detect the bridge puppet as a self alias for direction purposes, and exclude self from resolver attribution.
When designing a person-link resolver in any multi-source CRM, tag the user's own record explicitly (e.g. with a me tag), then exclude that record from candidate matches before deciding attribution. Pair this with bridge-puppet self-detection if the data sources route the user's outbound through a different identity than their primary account.