Connect by JBRH Open Connect

Memory from a phone call

When a call ends, voice.end_call produces four things in one place: a summary, a lead where there is one, memory, and any follow-up that was promised. What survives is what was said clearly enough to be worth keeping — a thin call is never summarised at all, and a name that might be a form of address is refused rather than stored.

Status
Available What this means
Audience
both
Channels
phone
In the app
#/calls, #/relationships
Last verified
Product version
6.3.2

What runs at the end#

Both engines end the same way. On the realtime path the worker posts to /engine/end, which runs the same voice.end_call the turn-based carrier path uses, so a workspace that switches engines does not get a different record. Model usage is booked into costs at the same moment.

That ending used to wait on the summary and the review — two model calls — inside one twenty-second request, and logged "end not recorded" for an ending the engine had in fact recorded. Now finish(defer=True) closes the row, books the cost, marks the digest as pending and answers; a background task runs the digest once. The practical consequence for you is that the record appears immediately and the summary and any memory from it land a moment later. A blank summary thirty seconds after hang-up is normal; a blank one an hour later is not.

Two filters before anything is believed#

ConditionWhat happensWhy
Fewer than two spoken lines and fewer than five words from the other partyNever sent to the summariserTen one-turn rows once carried an invented afternoon at the sales desk
no_answer — it rang and nobody picked upNo lead, no factsNothing was said, so there is nothing to learn
not_reached — it never rang at allNo lead, no factsThe dial, the dispatch or the worker failed; this is an operational fault, not an outcome
A greeting that could not be spokenRecorded as a silent failure, outcome not_reachedFive inbound calls once sat in silence and were logged as somebody hanging up before speaking

A conversation that never happened has its own word in the code, NOT_A_CONVERSATION, and the distinction between *nobody answered* and *it never rang* is kept rather than flattened. That matters for memory because an agent that writes "unreachable, not interested" from a line that never rang has manufactured a fact about a person out of its own outage.

Names, and why one is refused#

Speech makes names fragile. A transcript turns a form of address into a proper noun, a summariser writes "the caller" where a name should be, and once either is stored it is read back aloud on the next contact. identity.PROTECTED_MARKERS, with name_rejected, clean_name and scrub_names, sits on every door a name passes through — summariser output, lead capture, person upsert and connect_memory.remember — and every door it is read back through.

  • A form of address is never stored as a name.
  • fact_rejected refuses a name-keyed fact whose subject is a suffix, a pronoun or "the caller".
  • A person created by lead capture carries phone_key from the start, so the number is linked rather than orphaned.
  • A number that matches two person records resolves to the oldest, so a repeat contact does not quietly build a second, emptier history.

The visible behaviour is that Connect would rather hold no name than a wrong one, and will ask again next time. That reads as forgetfulness for about a second, until you consider the alternative — a business confidently addressing somebody by a word its transcriber invented.

Values that were spoken aloud#

A phone number, an email address or a reference code said out loud is the highest-value and least reliable thing on the line. The conversation layer notes what was heard as an entity_heard event naming the value, then checks the next two lines for a read-back, recording entity_readback {confirmed} when the other party agrees with it. A value that was never confirmed is exactly the sort of thing you should not let into a durable record without looking at it.

Promises get the same treatment. record_event refuses a follow-up time that shares no time word with the other party's latest time-bearing line, unless they just agreed to a time the voice said aloud. The tool answers "NOT recorded" so the model cannot claim a booking it did not make, and promised_unbooked is the finding for a promise with nothing behind it. Follow-up integrity is documented under follow-ups; what matters here is that a fabricated appointment never becomes a remembered one.

Questions#

Why is there no summary for a very short call?

Because it was below the floor: fewer than two spoken lines and fewer than five words from the other party is not enough for a summariser to work from, and asking it anyway produced invented detail. The record still exists with its times, cost and outcome — there is simply no narrative on top of it.

A fact from a call is wrong. What do I do?

Correct or forget the row in the memory viewer, at the contact tier where it was written. That changes the next piece of work on every channel, not just the phone. If the fact was a name, check the person record too — a wrong name is usually a wrong identity resolution rather than a wrong memory.

Does the transcript itself become memory?

No. The transcript and the summary are part of the record and stay readable from the conversation; memory is the much smaller set of durable claims written at the end. Keeping them separate is what stops a person's tier growing by a page every time they ring.