0101 — Tour-day arrival updates reach the leasing team on every channel; voice transfers the live call
- Status: Accepted
- Date: 2026-07-17
- Deciders: Fede
Context
On 2026-07-17, prospect Daniel Yagow called Camellia Apartments a few minutes before his 1:00 PM tour and said "I'm here to look at an apartment… I'm a few minutes early" (conv_voice_026faf88-77ee-473f-8ad9-5be96f5a4e8b). Clara gave him the buzz code and directions, the call ended resolved — and nobody on the leasing team was told a prospect was standing at the door.
Two structural gaps caused this:
- The tour-day update path is text-only.
leasing.notify_leasing_team(src/lib/tools/leasing.ts) exists precisely for this — its enum includesarriving_earlyandarrived, and its description says it is "the only way the team hears about it in real time." But its voice binding is deliberately empty (channels: ['text'],agents: []), on the assumption that "the voice Leasing specialist transfers a live caller instead." - That transfer assumption never fires for arrivals. The Leasing voice specialist does carry the ElevenLabs
transfer_to_numbersystem tool (conference transfer topm_phone_number,agents/clara/lib/voice-agents/leasing.config.json), but its only condition is "The caller asks for a human or the issue is beyond any sibling's scope." An arrival/running-late/at-the-door update satisfies neither — Clara self-serves the access answer and the call ends with the team unaware.
Net effect: on text channels the team gets a real-time email for tour-day updates; on voice — the channel a prospect standing at the door is most likely to use — they get nothing.
A secondary observation from the same call (out of scope here, tracked separately): the topic classifier filed the call as resident_inquiry/access because the taxonomy has no tour-arrival category.
Decision
Tour-day time-sensitive updates from a prospect with a scheduled tour must reach the leasing team on every channel. The channel-appropriate mechanism differs:
- Text channels (SMS/email): unchanged.
notify_leasing_teamemails the on-site team, as today. - Voice: transfer the live call to the leasing team (
transfer_to_number→pm_phone_number, conference transfer), rather than emailing. Rationale (Fede's call): a prospect physically on-site is the highest-intent moment in the funnel; a live human voice beats an async email the team may read after the prospect has left.
Concretely:
- Widen the
transfer_to_numbercondition on the Leasing voice specialist (and the triage/unknown-caller specialists that can field a prospect before hand-off) to include: a caller with a scheduled tour reporting a tour-day logistics update — arrived / at the door, arriving early, on the way, running late, can't find the office, wants to nudge the time. - Prompt guidance: Clara may still answer the access question (buzz code, directions) first — self-serving the door is good — but she must then transfer so a human greets the prospect. Announce the transfer with the standard connect line ("Let me connect you with someone on the team." — owner ruling 2026-08-15,
voice-agents/human-transfer-connect.ts). - Fallback when the transfer doesn't complete (no answer / caller hangs up): the
call-endedpipeline already detects whether atransfer_to_numbersystem tool-call completed (src/app/api/voice/call-ended/route.ts, emergency-relay gate pattern). Reuse that detection to send the existingnotify_leasing_teamemail post-call, so a failed transfer degrades to today's text-channel behavior instead of silence.
A future reader can test code against this decision: any channel where a prospect can say "I'm here for my tour" and the leasing team is not synchronously alerted (voice: transfer; text: email; any: fallback email on failure) violates this ADR.
Consequences
- The leasing team's phone becomes part of the tour-day loop: transfers will ring
pm_phone_numberfor arrivals, not just escalations. If that number is unstaffed at tour times, transfers fail into the email fallback — acceptable, but worth watching after rollout. - The
transfer_to_numbercondition change lives in the specialist config JSONs. Per the known ElevenLabs specialist-sync gap, prompt changes auto-sync but existing tool config changes do not — shipping this requires a manual PATCH of the affected EL agents'transfer_to_numbertool after merge (verify withscripts/sync-specialist-transfers.ts/specialist-transfers-drift.test.ts). - The call-ended fallback introduces a second sender for
notify_leasing_teamemails. It must dedupe against a completed transfer (only send when no transfer completed) so the team never gets both a live hand-off and a redundant email. - Follow-up (separate ADR/card): add a tour-arrival category to the topic taxonomy so these calls stop being filed as
resident_inquiry.
Alternatives considered
- Email-notify on voice (bind
notify_leasing_teamto the voice agents). Consistent with text, fire-and-forget, no dependence on someone answering the phone. Rejected: minutes-level email latency is wrong for a prospect physically at the door; Fede chose the live hand-off. - Email + offer transfer. Most coverage, but double-notifies the team on every successful transfer and complicates Clara's decision surface. Rejected as primary; its useful half survives as the failed-transfer email fallback.
- Do nothing (status quo). The comment in
leasing.tsclaims the voice specialist "transfers a live caller instead" — but the transfer condition never matches arrivals, so the claim is false in practice. Rejected.