Vendor Scheduling Demo — Run of Show
For the Camellia staff meeting · 2026-07-30 · Everything below runs on the sandbox property (appfolio-45, spoken of as The Willows on every call — the company name is never said to a vendor). Fede drives; the audience is the people who make these calls by hand today. The frame for the room: this is the phone-and-paperwork part of a vendor job done for you — the PM keeps every decision (which vendor, what money), Clara does the dialing, the re-dialing, and the writing-it-down.
What changed overnight (why this demo is safe to give)
- The whole loop is machine-verified. The offline rehearsal rig ran the exact production code path end to end on the live ledger: job scheduled → real Outlook event created → vendor calls back, is recognized → the same work order moves to the new day → the calendar event follows → no duplicate job. 14 of 14 legs green (2026-07-30, work order WILL-002145).
- The rig caught a real bug before the demo could. On inbound callbacks, Clara answering with the property's own name was being read as "the wrong company answered" and every reschedule refused. Fixed with a regression test (PR #4985) — this must be merged and deployed before a live callback demo; the offline proof above already ran with the fix.
- Vendors who identify only by company name now bind to their job (full parity with phone recognition — founder decision), in PR #4919, final checks running.
- Seven PRs merged overnight hardening the path: test-dial safety rails, manual-reschedule calendar sync, calendar provider guard, the turnover-SMS wedge (a PM's "yes, send the vendor" now works at every door), triage saying "purchase order" never "PO", and the demo-loop rig itself.
The story in one breath
A make-ready job needs a vendor. Clara calls the vendor herself from The Willows' own phone line, gets the job on their schedule like a human coordinator would — no permission-asking, PO spoken digit by digit, never approves a price — and when the call ends, the work order is scheduled and the visit appears on the property's Outlook calendar. Later the vendor calls back to move the day; Clara recognizes them from the number, knows exactly which job it is, and the reschedule lands on the work order and the calendar without a human touching anything.
Cast & numbers
| Role | Who / number |
|---|---|
| Clara (outbound vendor agent) | dials from The Willows' line +1 844 285 3526 — the vendor's phone shows the property's number, and any callback rings Clara, never the PM |
| The vendor ("Miracle Method of Denver") | Fede's cell +1 404 285 9387 — seeded as the vendor's contact number |
| The job | PO 90760 · tub/shower resurface · unit 201 (re-check after re-seeding — the seed rotates units) |
| Property calendar | propflowaicalendar@outlook.com (The Willows' connected Outlook leasing calendar) |
Pre-flight (10 minutes before)
- Re-seed the PO book (seeded POs go stale after 24 h) and note which unit each PO landed on this time:
DATA_BACKEND=dynamodb DYNAMODB_TABLE_NAME=propflow-prod AWS_REGION=us-east-1 \ npx tsx scripts/dev/seed-willows-pos.ts --apply --key-real-vendors - Persona check — Fede's number must read as the vendor, not a prospect:
bash ~/.claude/skills/willows-persona/persona.sh status - Prompt sync check (was verified in sync today; cheap to re-run):
npx tsx scripts/verify-vendor-outbound-prompt.ts - Open the proof surfaces before dialing: the Outlook calendar (week view), the work-order page, and the vendor's schedule page in the app.
- Phone on speaker, room quiet. Silence other devices — the dial arrives within ~10 s of the command.
Act 1 — Clara calls the vendor ~2 min
npx tsx scripts/vendor-calling/test-dial.ts \
--job "resurface the tub and shower walls" \
--vendor "Miracle Method of Denver" \
--unit <unit-from-seed> --pm "Fede" --po 90760 \
--i-understand-this-dials
Fede answers as the vendor's front desk:
"Miracle Method, this is Fred."
What to point out to the room while it happens (in their terms):
- Clara listens first. She waits for the greeting instead of talking over the pickup — and because the greeting named the shop, she doesn't re-confirm it. New behavior, shipped today.
- Identity leads, property-first: "Hi Fred — this is Clara calling for Fede over at The Willows." One warmth beat, then the job on the next turn.
- PO digit by digit ("nine-zero-seven-six-zero") with the unit and trade beside it — never a bare number.
- Offer a day/time as the vendor ("Thursday morning work?"). Clara captures, never approves — if you push for a price commitment she declines and takes it for the PM.
- Say a plain goodbye — the close and hang-up come in one turn. Don't ask for a human transfer this run (no transfer target is armed; she'll decline it honestly, which is correct but not the demo).
Act 2 — the paper trail appears ~2 min
- Work order: scheduled date/window stamped, timeline shows the call outcome and who Clara spoke with ("Spoke with Fred.").
- Property calendar: a new event on
propflowaicalendar@outlook.com— "🔧 Miracle Method of Denver — resurface…, Unit … (arrival window …)". It's a mirror of the work order: marked free so it never blocks tour availability, and the body says edits there don't sync back. - PM notification: the property inbox gets the one-line outcome.
Timing note: the writes happen when the call ends (post-call extraction) — give it ~30–60 s before refreshing.
Act 3 — the vendor calls back to reschedule ~2 min
From the same cell, Fede calls The Willows' line back: +1 844 285 3526.
- Clara recognizes the number against the outbound session: "Hi, is this Miracle Method of Denver? It's Clara at The Willows — are you calling about the resurface at unit …?" No re-introductions, no "how can I help you" cold start.
- Fede:
"Yeah — Thursday's not going to work anymore, can we push it to Friday?"
- Clara takes the change and closes. After hang-up: the work order moves to the new day, the calendar event moves with it, and the PM gets a "moved to a new day" note.
Two rules that make this work: call back from the same phone Clara dialed (recognition is phone-keyed), and the reschedule is written at call end — in-call she promises it, she doesn't claim it's done.
What NOT to claim (honest edges)
- Clara doesn't propose times off a calendar yet. She asks the vendor's availability and books what they offer. Slot-proposal from real availability is Phase 4, held on open product decisions (auto-book autonomy; occupied/vacant stamping).
- No real vendor has ever been dialed. All 60+ outbound calls to date are bench calls (Fede / QA robo-vendor). This demo is the same bench, played honestly.
- Company-name-only reschedules are merging, not merged. A vendor calling from an unknown phone who identifies only by company name binds to their job in PR #4919 (final checks) — until it deploys, the demo callback should come from the same phone Clara dialed.
- In-call, a reschedule is a promise. The write is post-call by design (it survived a grader that tried to make her bless changes live).
If it goes sideways
- Clara says a wrong property name → the seed or record drifted; the record is
PROP#appfolio-45name="The Willows". Abort, re-check, redial. - Callback routes to leasing instead of vendor flow → persona drifted; re-run
persona.sh vendor, call again. - No calendar event → work order page is still the truth (the app's vendor schedule renders from the work order even when the mirror fails); say so and move on.
- PO refused at dial time → the PO gate is working and the seed is stale; re-seed (pre-flight step 1).
Where this stands for Camellia — the honest boundary list
What separates "great demo" from "Camellia turns it on Monday." Each item is a decision or a deploy, not a research project.
| Gate | State | What it takes |
|---|---|---|
| Deploy the two in-flight fixes | PRs #4985, #4919 | Merge on green + Vercel deploy — without #4985, live inbound reschedules refuse; without #4919, unknown-phone vendors can't move their job. |
| Dial a real vendor | Never done — by design | Every outbound call to date is bench (Fede / QA robot). First real dial is a deliberate go from Fede + Camellia, starting with one friendly vendor and one job class. |
| Purchase-order sync for Camellia | Zero PO rows in prod | Camellia's vendors already print AppFolio purchase-order numbers on their invoices; enabling the sync gives Clara the numbers she speaks and makes ~$6.7k of 2026 invoice spend attributable on day one. Human decision, one flag + a sync run. |
| Inbound resolution rate | 78% autonomous on the 66-call replay corpus | Up from 70% baseline overnight; the ≥80% target is one measured prompt iteration away (two of the six remaining failures are grader artifacts, not bad calls). PR #4938 holds the current improvement. |
| Transfer target | Not armed | When a caller genuinely needs a human, Clara needs a number to hand off to during office hours — a config decision (front desk vs Joanna's line), not code. |
| Vendor email & invoices | Detection scoped, decisions parked | Schedule-bearing vendor email and invoices are currently understood and discarded. The lifecycle plan, mined 2026 spend ($39.6k), and the decision list (trusted-sender policy, metered parsing spend) live in the companion doc: Vendor Lifecycle: Coordination → Job Done → Paid. |
After the demo
- Restore Fede's persona:
bash ~/.claude/skills/willows-persona/persona.sh restore(coordinate with the turnover-handoff thread if it still needs vendor mode). - Caller-ID question, answered: outbound already presents each property's own line (Camellia would show
+1 844 510 1007) and callbacks ring Clara — this is shipped behavior, nothing to build. Never use a property'sofficePhoneas caller ID (for Camellia that's a forwarding number to the PM's cell).