Plan · In progress

One conversation per person

2026-08-05 · from the “multiple creations for convos” ticket + Monday’s standup · full technical doc ships with the PR as docs/planning/conversations-one-thread-per-person.md

Why the conversations page shows the same person over and over, why a message sent today could land on page 3, and the fix that's already being built.

The short version. Half the conversations list is repeats — the same person shown again for every phone call they ever made. We're collapsing the list to one row per person: open it and you see their calls, texts, and emails as one message history, newest activity always on top. Nothing gets deleted — every call and its recording stays underneath. The first piece is written and tested; the PR goes up for review now.

What the data says (production, measured Aug 5)

801conversation rows for real customers
395actual people behind them
50.7%of the list is a repeat of someone already on it
126rows for one single repeat caller

Also checked: every multi-row person maps to one phone number (or their own email), so grouping by person can never merge two different humans into one row.

Why it happens — three separate problems

1 · Every phone call opens a brand-new conversation

The moment a phone rings, a new conversation row is created — no check for whether that person already has one. A repeat caller gets a new row every single time. Those per-call rows are also our call log (recording, summary, review links), which is exactly why the fix must not delete them.

2 · There's no single place that decides which thread a message lands in

Six different pieces of code independently answer “which conversation does this message go into?”, each keyed differently. The manual follow-up text from this week landed inside a months-old phone-call thread because the picker matches on bare phone number with no preference for the right kind of thread. This is exactly the “single point of entry” Fede called for at standup.

3 · The list can sort a fresh message months back

The message did bump the conversation’s “last activity” correctly on the server — but the page sorts unknown-caller threads by an older captured-date field that shadows it. That thread sorted as June 1, fell outside the default 30-day window, and needed “all time” + page 3 to find. A second, quieter bug let a stale background save move a thread backwards in the list.

The fix — two layers, riding what we already built

Now: the page shows people, not rows (PR going up)

Next: one single point of entry for writing to a conversation

One shared person-first resolver decides the target thread for every outbound message — person record first, right property, right kind of thread, most recent wins — replacing the six independent pickers. That's what stops new wrong-thread messages at the source. Tracked in issue #5004; ships as its own PR right after.

What we deliberately did not do

How we'll know it worked

Unit tests pin the grouping, the sort fixes, and the never-bury rule. After deploy: the conversations page at Camellia shows ~one row per person instead of 730 rows, and this week's buried follow-up sits on page 1 with its real send time.

PropFlow Docs