A fact learned on a call, end to end
A fact said on the phone becomes contact memory at the end of the conversation, through voice.end_call, and is read on every channel from the next piece of work onwards. Between being spoken and being stored it passes a summariser floor, a name guard and — for a number, an address or a code — a read-back check. Anything that fails one of those does not become a fact.
The stages#
- TRIGGER — the line rings inbound, or
chase_phonedrains a phone follow-up and places the call - USER / EXTERNAL EVENT — a person speaks;
start_of_speech_sensitivity=HIGHmeans a one-word answer starts a turn - AUTH / WORKSPACE RESOLUTION — the signature is checked and the handler runs inside the owning workspace, not merely beside it
- INGEST / REQUEST — the worker posts each spoken sentence to
/api/voice/engine/spokenand each event to/engine/event - CANONICAL RECORD — the
callsrow, pluscall_eventsstoring every normalised event once behind a partial unique index on the signature nonce - CLASSIFICATION / RESEARCH / REASONING —
entity_heardnames a spoken value and the next two lines are checked for a read-back - KNOWLEDGE + MEMORY + RULES — the brief was rendered once at the start; nothing written now reaches this conversation
- AUTONOMY / APPROVAL — a promised time is refused unless it shares a time word with what was said, or was agreed aloud
- ACTION / PROVIDER — the model answers; the reply is re-checked against the guardrails after the fact
- RESULT — the conversation ends and
hangup_byis attributed to caller, model, owner, engine, carrier or agent - RELATIONSHIP / TIMELINE / MEMORY —
/engine/endrunsvoice.end_call: summary, lead, memory, follow-up, with the digest deferred to a background task - AUDIT / USAGE / NEEDS YOU — model usage is booked into
costs, and line health escalates into Needs You when a line stops being reachable
Stage by stage#
| Stage | What you see | What changes | What can fail |
|---|---|---|---|
| The line rings | An active conversation on the Phone screen | A calls row exists | not_ready when no worker has checked in for 90 seconds, so the drain retries |
| A value is spoken | Nothing on screen | An entity_heard event naming what was heard | A misheard digit that is never read back |
| A time is promised | Nothing on screen | A follow-up, or nothing at all | The tool answers NOT recorded, so no booking is claimed |
| The conversation ends | The record closes immediately | Cost booked, digest marked pending | Nothing — the digest runs separately, so a slow model cannot lose the ending |
| The digest runs | Summary and any memory appear | Contact memory is written | Below the floor, nothing is summarised at all |
| A week later | An email reply that knows the fact | Nothing new | The memory was written on a different person record |
The three checks between spoken and stored#
- The floor. Fewer than two spoken lines and fewer than five words from the other party, and nothing is sent to the summariser. Ten one-turn records once carried an invented afternoon at the sales desk; not asking is cheaper than correcting.
- The name guard.
PROTECTED_MARKERS,name_rejected,clean_nameandscrub_namesstand on every door a name passes through, includingconnect_memory.remember. A form of address is never a name, andfact_rejectedrefuses a fact keyed to a pronoun, a suffix or "the caller". - The read-back. A number, an address or a code gets an
entity_heardnote and the following two lines are examined for confirmation, recorded asentity_readback {confirmed}. An unconfirmed value is exactly what you would want a person to look at before it becomes durable.
None of the three makes a transcript trustworthy on its own. What they do is stop the two failure modes that damage a relationship: a confident wrong name, and a fact invented out of an outage.
Using it on another channel#
Contact memory belongs to the person, not to the number they rang from. So a preference stated on the phone on Monday is in front of Connect when the same person emails on Friday, provided the two resolved to one person record. That is the payoff for the identity work: a contact created by lead capture carries phone_key from the start, and a number matching two records resolves to the oldest rather than quietly starting a third history.
The failure to look for, when a spoken fact does not turn up on email, is almost never memory. It is two person records for one human. Merging them in relationships restores it everywhere at once.
Questions#
How long after a call does the memory appear?
The record closes immediately and the digest runs as a background task, so the summary and any memory follow a moment later. That split exists because the ending used to wait on two model calls inside one twenty-second request and log 'end not recorded' for an ending that had in fact been recorded.
If nobody answered, does Connect record anything about the person?
No facts and no lead. A conversation that never happened has its own word: no_answer rang and nobody picked up, not_reached never rang at all. Keeping those apart stops an outage being written down as a fact about somebody's willingness to talk.
Can I correct a fact the call got wrong?
Yes — edit or forget the row at the contact tier, from the viewer or the memory sheet. It changes the next piece of work on every channel. If the error was a name, check the person record as well, because a wrong name is usually a wrong identity match.