# Identifying the caller

`identify_caller` resolves the calling number against the workspace's own people. If two records share that number it takes the **oldest**, deliberately, so the same call never lands on a different record twice. An unrecognised number is not a problem to be solved with a guess: the call proceeds with an unknown caller, and nothing invents a person.

- **Status:** Available
- **Audience:** both
- **Channels:** phone
- **In the app:** #/calls
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/phone/caller-identity/

## The key, and the day most contacts did not have one

Resolution is only as good as the key it matches on. A number typed by hand, a number from a carrier and a number in an email signature are three different strings for one telephone, so people carry a normalised `phone_key` and matching happens on that.

Contacts created by lead capture now carry the key from the moment they are created. They did not always: on one host, **23 of 25** had none. Every one of those was a person who would ring back and be met as a stranger by a system that already had their record open in another screen.

> **Note** A missing key is silent. Nothing errors, no screen shows a warning, and the only symptom is a returning caller treated as new — which reads as "the AI does not remember me" rather than as a data fault.

The number is a key first and a hint second, and what it is allowed to say about place is narrow on purpose. The country comes from the dialling code; a city comes only from an Indian landline's STD code. **A mobile number never names a region** — since number portability a series says nothing about where its owner lives, so none is guessed from one. Where a place does come out, it makes a language likely rather than certain, and [regional speaking style](/docs/phone/regional-speech/) covers what is done with that.

## Two records, one number

Shared numbers are ordinary: a family business, a reception desk, a husband and wife on one mobile, a duplicate created before anybody merged it. Something has to choose, and the choice has to be **stable** more than it has to be clever.

`identify_caller` takes the oldest of the matching records. The reasoning is that the oldest carries the most history, and — more importantly — that the same input produces the same output on every call. A heuristic that picks the most recently active record would move a caller between records depending on what happened in between, which is how one person's history ends up split across two rows that each look half-complete.

| Situation | Result | What to do about it |
|---|---|---|
| One match | That person | Nothing |
| Two or more matches | The oldest | Merge the duplicates; the merge tool is in the relationship console |
| No match | An unknown caller | Nothing is invented. A record may be created from the call if it produced a lead |
| No usable key on an existing record | No match, though the person exists | Fix the record; the next call will resolve |

## A caller who gives no name

They stay unnamed, and this is a rule rather than a gap. The strong temptation in a voice system is to fill the field with whatever was heard — a form of address, a company, "the caller" — because an empty field looks like a failure. Each of those makes the record worse, and Connect refuses them explicitly: **a form of address is never a name**, and `fact_rejected` turns away a name-keyed fact that is a suffix, a pronoun or "the caller".

[Names heard on a call](/docs/phone/names-on-calls/) sets out every door a spoken one has to pass through before it reaches a record. The short version is that the guards are on the write path and on the read-back path, so a bad value is neither stored nor said aloud.

A call that was never a conversation produces nothing at all: `_capture_lead` creates no lead from `no_answer` or `not_reached`, so a ring that nobody answered does not leave a half-person behind.

## What is verified today

Caller identification was reconciled on 2026-09-10 against `backend/app/voice_region.plan` and `voice_region.geography` at `f5ea518`. The normalised key, the oldest-record rule and the refusal to invent a person or a name are unchanged. What did change is what the resolved record is then used for: a remembered `preferred_language` on it is spoken from the first reply, and a city or state on it makes a language likely without assuming it. Neither is inferred from a mobile number.

## Questions

### Why did a returning caller come through as unknown?

Almost always a missing or differently-formatted key on their record rather than anything about the call. Check the person's number as stored: resolution matches the normalised key, so a number kept in a free-text note or with a different country prefix will not be found.

### Can I choose which record a shared number resolves to?

Not per number — the rule is deliberately fixed at the oldest so that resolution is repeatable. If the wrong person is being reached, the underlying issue is usually two records that should be one; merging them removes the ambiguity rather than working around it.

### Does identification happen before the greeting?

The brief is rendered before the call starts, so the contact's facts are in front of the model from the first turn. The greeting itself is pre-synthesised audio chosen ahead of the call and does not vary by who is calling.

## Related

- [Names heard on a call](https://connectbyjbrh.com/docs/phone/names-on-calls/)
- [A returning caller](https://connectbyjbrh.com/docs/phone/returning-caller/)
- [The call brief](https://connectbyjbrh.com/docs/phone/call-context/)
- [Leads captured from a call](https://connectbyjbrh.com/docs/phone/lead-from-call/)
- [Why the machine proposes a merge and a person disposes](https://connectbyjbrh.com/research/one-person-many-channels/)

## What this page is based on

- Reconciled 2026-09-10 against `f5ea518` — `backend/app/voice_region.plan`, read from the code rather than its docstring
- Connect phone source pack — `docs-source/sources/PHONE.md` §10, identification and names
- Connect phone source pack — `docs-source/sources/PHONE.md` §9, calls that were never a conversation
- Connect capability registry — `docs-source/facts.py` (`cross_channel_identity`, `duplicate_merge`)
