Connect by JBRH Open Connect

Creating a follow-up, end to end

A commitment is spoken or written; the guard checks the proposed time against what was actually said; due_at resolves it in the line's timezone; follow_up_channel picks the channel; schedule writes one row — unless that person already has one at that instant. The path is built to fail loudly rather than book a time nobody named.

Status
Available What this means
Audience
both
Channels
phoneemailwhatsapp
In the app
#/follow-ups, #/calls
Last verified
Product version
6.3.2

The thirteen stages#

  1. TRIGGER — somebody makes a commitment. "I'll ring you back at three", "I'll send the quotation tomorrow", or a written promise on a thread.
  2. USER / EXTERNAL EVENT — the words arrive: a caller speaking on a line, a message delivered by a provider, or a person filling in the form on the follow-ups screen.
  3. AUTH / WORKSPACE RESOLUTION — the line, mailbox or session decides the workspace. Every downstream record is scoped to it, and row-level security backs that boundary beneath the application.
  4. INGEST / REQUEST — on a call, schedule_follow_up carries the caller's last lines and the voice's own alongside the proposed booking. Without that evidence the next stage has nothing to check against.
  5. CANONICAL RECORD — the commitment attaches to the canonical Person, not to an address. A contact created by lead capture carries phone_key from the start, so a call-back has a number to reach.
  6. CLASSIFICATION / RESEARCH / REASONING — follow_up_channel reads what was promised: a call-back becomes phone, a person's own work — "send the quotation", "review the recording" — becomes task, and "no follow-up needed" schedules nothing at all.
  7. KNOWLEDGE + MEMORY + RULES — the time guard runs. record_event refuses a when that shares no time word with the caller's latest time-bearing line — conversation.when_mismatch, in English, Telugu and Hindi — unless the caller has just agreed to a time the voice said aloud, which is when_agreed. A refusal answers NOT recorded, in those words, so nothing downstream can claim a booking. A read-back is asked for only when the caller neither named a time nor agreed to one.
  8. AUTONOMY / APPROVAL — none is needed to create a row. Creating a commitment is not acting on it; the approval question belongs to execution, later.
  9. ACTION / PROVIDER — due_at turns the promised words into a time in the line's timezone: "in 10 minutes", "tomorrow 11am", "Friday 3pm", "today evening". Nothing usable falls back to 11:00 tomorrow. Then schedule writes the row.
  10. RESULT — one row, with a person, a when, a channel and a reason. Or no row: the duplicate test refuses a second follow-up with the same *when* for the same person, and the guard refuses a time nobody said.
  11. RELATIONSHIP / TIMELINE / MEMORY — the commitment appears on the person's record and is counted in what is open against them. It survives a merge, because a merge preserves follow-ups from both sides.
  12. AUDIT / USAGE / NEEDS YOU — the creation is recorded with who or what made it. promised_unbooked is the finding when a promise was made and nothing was captured behind it — a defect worth reviewing, not a silence.
  13. NEXT — the row waits for its due time, and then Executing a follow-up, end to end takes over.

Stage by stage#

StageWhat you seeWhat changesWhat can fail
CommitmentA conversationNothing yetA promise so vague nobody could act on it
EvidenceNothingThe caller's and the voice's lines travel with the bookingA booking attempted without them cannot be checked
ChannelThe channel on the rowphone, task or a message channelHuman work classified as a call, which then rings somebody about a document that does not exist
Time guardA read-back, or a refusalNothing on a refusalA time the caller never said — refused, and correctly
Due timeA timestamp in the line's clockThe row's whenA weekday resolving forward when the caller meant today
Duplicate testA refusal, or the rowNothing when it refusesTwo different promises due at the same instant collide
RecordThe row on the queue and the personThe open-commitment countNothing: the row and its history are written together

Where this flow refuses on purpose#

  • The time was not said. A mismatch between the proposed when and the caller's own time-bearing line is refused rather than parsed generously. Before that rule existed, one production call looped three times trying to book a time nobody had named.
  • The tool says NOT recorded, literally. The wording exists so a model cannot go on to tell a caller their appointment is booked when it is not.
  • No follow-up was needed. An empty queue after a call that required no chasing is the correct outcome, not a missed booking.
  • The same commitment already exists. Same person, same when. The older row stands, with the reason written closest to the promise.

Doing it by hand#

  1. Start from the person or the thread.

    Result The row attaches to the relationship and appears in the open commitments against them.

  2. Write the reason as a promise, a dependency and an exit condition.

    Result Whoever inherits it can act without reconstructing the conversation.

  3. Set the time you actually said, then pick the channel that keeps the promise.

    Result The duplicate rule protects you, and the right drain — or no drain, on task — picks it up.

Questions#

Why would a call end with no follow-up when I heard a promise?

Either the promise named no time and the guard refused the booking, or the classification decided nothing needed scheduling. promised_unbooked is the finding that distinguishes the two: it flags a promise with nothing behind it, which is worth reviewing.

Does creating a follow-up need anybody's approval?

No. Recording a commitment is not acting on one. The approval question arrives when the row comes due and the drain attempts something through the channel's own gates.

What if the caller says a time in a language other than English?

The time-word check runs in English, Telugu and Hindi, so a time named in any of those can be matched against the proposed booking rather than refused for looking unfamiliar.