From “Approved” to Keys in Hand: Closing Clara’s Post-Approval Gap
Scope: everything between “your application is approved” and move-in day — status answers, lease dates, deposits, specials, e-sign, key pickup — at Camellia today, generalized for every property.
1. What happened (the problem, verbatim)
Jacob Warren, unit 403 — approved 2026-07-27, move-in 2026-08-12. Called twice (Aug 3 + Aug 4). Both calls, Clara knew his status (“your application for unit 403 has been approved”, second call even “your move-in is set for August 12th”), then offered “next steps, move-in details, anything like that?”, he said yes, and she said the leasing team handles that and transferred. Both transfers reached nobody — the Aug 3 call ends with Jacob saying “Hello?” into 68 seconds of dead air. As of Aug 5 he is still unconverted, no deposit posted, portal not activated, 7 days before move-in. Nobody on the team was notified either time — both calls were stamped connected in our DB.
“your application for unit 403 has been approved” … “next steps, move-in details, anything like that?”
Clara to Jacob Warren, Aug 3 & Aug 4 calls — followed both times by a transfer to nobody
This wasn’t isolated. The 9-week dossier (5 sources: voice transcripts, prod conversations, Slack standups/site visits, ops channels, the Camellia inbox) found zero instances of Clara answering a post-approval question end-to-end. Every case: transfer or escalation — and when the escalation tooling failed, questions only got answered if a founder happened to catch the thread by hand.
Interaction evidence
| Case | What was asked | What happened | Status |
|---|---|---|---|
| Ekene Nwosu renewal, 7/20–21 |
Does the 1-month-free promo apply to her renewal? | The escalation tool failed silently (nobody paged). Fede caught the thread himself and manually authorized a one-time exception (2 weeks free), replying as Clara via takeover. | Human-authorized — correction 2026-08-05: an earlier review mislabeled this “fabricated”. The defect is the silent escalation failure: without Fede noticing, the question would have died unanswered. |
| Hayley Bannochie, unit 612 7/18 |
Pricing + the special; then “does it apply to a 6-month lease?” and “must the concession be repaid if the lease is broken?” | Clara: “1 month free on select homes… 6-month and 12-month at the same rate” — never stating the special is 12-month-only. | Both follow-ups never answered by anyone, to this day. |
| Hayley’s lease dates | “moving in 8/20, why does my lease say 9/1–1/31? that’s only 5 months” | Read aloud in the Aug 4 standup; AppFolio now shows the correct 9/1/26–2/28/27. | Document she received likely predated a correction — confirm with Joana. |
| Transfer black hole systemic |
— | Of 30 human transfers at Camellia in 4 weeks, 8 (27%) never reached a human (4 voicemail/IVR, 4 dead air). The DB stamped most connected (voicemail is documented in code as indistinguishable from pickup; verdict fails open). |
No SMS fallback, no PM alert, no callback — post_transfer_no_pickup is consumed by nothing, and call-ended marks every voice conversation resolved unconditionally. |
| Silent money bug unit 615, Dylan S., 6/15 |
— | Term set to 7/1 with 6/15 move-in → proration silently $0. | ≈$613 never billed. A lease-date/proration auditor would have caught it. |
| Jace, pre-signing call voice, conv_voice_44e2db3e |
Utility questions before signing — what’s included, what he’d be billed. | Clara answered, but the answer was verbose and partially wrong: it came from a stale knowledge note written as prose, not as something a person says out loud. Since corrected to the team’s verbatim answer. | Lesson recorded: knowledge must be written for voice — short, speakable, one fact per line. A paragraph that reads fine on a screen becomes an unlistenable answer on a call, and length hides the error inside it. |
| E-sign 422 7/13 |
— | AppFolio’s send-to-portal blind-fails if any financially-responsible signer lacks an email. | Lease never reaches the tenant, nothing tells us. |
Also live right now: unit 405 (Jace Weaver + SadieKate Ball) screened, undecided, desired move-in was Aug 6.
2. Why (root causes, from the code audit)
- Clara is built to stop at the application. Prompt: “The leasing team handles application review. Your job is to get the prospect in the door” (
clara-leasing.ts:625); application status is on the CANNOT-help list with a scripted punt (:558) that no tool enforces. - She’s blind. No stage/approvedAt/unit/lease data in her voice or text context; no
get_application_status/get_lease_status/get_move_in_detailstool. Only a lagging free-textaiNotessummary. - Approval = do-not-contact. Stop-conditions treat applied/approved as “follow-ups no longer appropriate” — no acknowledgment message class exists (the code names this as an open product decision, Trello
ydZuuhzP). Nothing fires toward the applicant on approval — no email, no SMS, no workflow. - No lifecycle between
approvedandlease_signed. No lease_sent / out-for-signature / move-in-scheduled stages; the approved-but-no-lease window has no PM reminder kind, no SLA, no review-queue lane. Only visibility: a 30-day filter in a weekly owner report. - Knowledge can’t hold the answers.
securityDepositis a single number (can’t express $300/$400 by unit type — prod says 300, wrong for 2BRs);Concessionis free text (no term eligibility, no mechanics); no applications/move-in policy section exists anywhere inPropertyKnowledge. - Transfer failure is invisible (see above) and resolution is unconditional.
3. The policy
Verified from 2 years of Camellia’s AppFolio ledger + Sean’s statements, Aug 4.
| Rule | Value | Evidence |
|---|---|---|
| Lease start | Always the 1st of a month. Move in any earlier day; stub is prorated. | 50/51 new leases since 2025-08 start on the 1st (regime tightened mid-2025); 26/28 mid-month move-ins → lease from next 1st |
| Term anchor | Term counts from the 1st of the subsequent month (“the 6 or 12 months starts on the first of the subsequent month” — Sean) | Sean, Aug 4 standup, verbatim |
| Lease end | Always end-of-month: anchor + term − 1 day | 47/47 recent leases end EOM |
| Terms offered | 6 or 12 months only — for BOTH new leases and renewals (Fede, 2026-08-05). Renewals additionally offer month-to-month (most common renewal outcome: 30 MTM / 29 6-mo / 20 12-mo) | Owner statement; renewal_summary |
| Proration | monthly ÷ actual days in that month × days occupied, rounded to whole dollars. Applies to rent + utility fee + parking. Adjustment line if move-in slips. | 45 stubs tested; every discriminating case fits actual-days (e.g. $1,150, 12 days of 31-day Aug → $445) |
| Security deposit | $300 studios/1BR · $400 2BR (flat, never a month’s rent). Pre-2020 leases grandfathered at $200, never topped up on renewal. unit_directory.DefaultDeposit is abandoned — ignore it. | 38 recent leases, zero cross-tier violations; unit 208 shows a $100 top-up correcting to the 2BR tier |
| Application fee | $38 per applicant | 95 charges at $38, multiples for co-applicants |
| Utilities (corrected 2026-08-05) | Per-lease billing mode, mid-migration: leases carrying the new utility addendum are billed usage-based via Conservice; all other tenants stay on the legacy flat monthly fee ($40/$45 in the ledger) until their current lease ends — some until 2027. New signers start on Conservice. Tracked today in a manual spreadsheet; Conservice has already mis-billed flat-rate tenants (units 310, 502 — charges backed out). Clara must know which mode a given lease is on before answering utility questions. | Kenya/Erika email thread “Utilites” 7/21–7/30 (verbatim: “we will back out those charges and keep them on the flat rate billing”); Conservice resident invites + move-out final bills; ledger flat charges = legacy cohort |
| Move-in special | 1 month free — new leases only (incl. transfers per Kenya 7/8: “we cannot differentiate… once we get down to only 7 apts available we can remove it”), 12-month terms only, mechanics = first month free, regular rent from month 2 — never amortized. Website popup now says “on new move-ins” (shipped today, camellia-site #13). | Sean Aug 4; Kenya email 7/8; Fede |
| Renewals | Start day after prior term ends (the 1st), EOM end, contiguous | 79/79 renewal starts on the 1st; 15/15 contiguous |
| Open questions | (a) the three 14-month leases written 2026-03-01 (batch decision?), unit 603’s 5-month, unit 402’s mid-month start; (b) | ask Joana/Sean |
4. What the industry does
- The approval→signed window is the industry’s uncovered middle. Every AI leasing assistant stops at the tour (AppFolio Lisa, Realm-X, Funnel, Knock, Zuma). EliseAI brackets it — tours on one side, a post-SIGNING Move-In module (checklists, insurance verification) and Lease Audits (signed lease vs ledger) on the other — but does not advertise covering approval→signature itself. Entrata named it (June 2026, “Autonomous Lease Progression”, no metrics). AppFolio’s native automation: exactly two identical reminder emails (+24h/+48h) then silence; deposit reminders exclude future tenants by design.
- Defensible SLA (Buildium, corroborated by TAA form + Yardi operator docs): approval communicated same day → lease sent same day → 48–72h signing window. No published post-approval nudge cadence exists anywhere — whatever we build is a design choice, and a differentiator. 95% of residents call transparent lease-signing essential; “applicants often don’t know what happens after they’re approved, so they assume the worst or move on.”
- Renter pain is evergreen: a Reddit “approved, still no lease” thread has run for four years. Vendor failure modes to design against (EliseAI operator complaints): the handoff void (“supposed to send to an agent — I’ve never had an agent respond”), bots re-engaging threads a human took over, over-messaging.
- Compliance rails for this stage: conditional approval = FCRA adverse-action notice (low trigger threshold); deadline extensions must be uniform written policy, not agent discretion (24 CFR 100.65 reaches deposits/lease terms/processing delays); reasonable-accommodation path must be able to extend deadlines and never raise a deposit (100.203 escrow rule); voucher holders can’t be excluded by rigid move-in deadlines (24 CFR 982.305 inspection timeline); AI bots must honor free-text opt-outs (FCC 24-24) and never auto-refuse vouchers (PERQ consent decree). Never announce approval-with-conditions or denials via AI (Yardi operator SOP: humans deliver adverse outcomes).
5. The plan
Phase 0 — this week, no schema (stopgaps)
Website special copy scoped to new move-ins✅ shipped (camellia-site #13, deployed).- “After You Apply / Move-In” section entry in Camellia’s
PropertyKnowledgesections[]— ships today through the existing ingest → prompt/voice →get_property_detailspath. Content from §3 + whatever Joana’s docs add. - Ops fixes now: Joana to call Jacob (unit 403, move-in 8/12, 3 signers, no deposit posted) and decide unit 405 (move-in date passed); answer Hayley’s two open questions; confirm her document was corrected.
- Transfer honest-labeling + pinned recordings — in final review. Reclassify
connected→no_pickupwhen the post-transfer transcript has no substantive human turns, and pin the recordings so the call can be replayed. Per decision D, that is the whole scope: no caller SMS, no PM chase, no un-resolve. Real-time Twilio dial-status callback remains the deeper fix (ticket). - Listing syndication audit (ticketed): the advertised special and deposit in the Zillow / Apartments.com ILS ads do not match current policy. The team is fixing the source in AppFolio now; an automated audit that catches ad-vs-policy drift is ticketed, not built.
Phase 1 — basics (status 2026-08-05)
- D1 — Lease-answer engine + test harness: built, review rounds addressed, merging (PR #5436). Proven by a blind A/B against production on the 10 real failure cases from §1:
The engine itself: pure date/proration arithmetic (
Measure Production today New engine Answers or escalates (never dead-ends) 0 / 10 10 / 10 Correct next steps 4 / 7 10 / 10 Fabrications 2 0 Voice verbosity Tied — disclosed gap, not a win. The fix is gated in the Clara-wiring PR, which must flip this to a win on replay before any of it goes live. computeLeaseDates,computeProration,auditLeaseDates), anApplicationLeasePolicyschema (terms, start convention, deposit tiers by bedroom, fees, structured concession rules), an answer engine grounded in AppFolio application/tenant data, and a subscription-powered eval harness seeded with the real cases (Jacob, Hayley’s date email, free-month-on-6-months=no, spread-out=no, renewal-exception=never-fabricate, 2BR deposit=$400, 18-month=escalate) + synthetic variants. Graders deterministic on dollars/dates, LLM judge on no-fabrication. - D2 — L4 lease modification: runner endpoints merged; review lane in final review; detector deliberately dark.
modifyPendingLeaseL4+resendLeaseForSignatureL4(with preflight: signer-email check to kill the 422 class; refuse on executed leases). The PropFlow-side review lane — engineering approval required before any execution — is in final review. The detector that would feed that queue is not wired up: it stays dormant until we turn it on, after the Willows live proof.
Scope note: lease modifications go through the internal engineering review queue — the same lane as outbound vendor calls and collections — not PM approval. Enables “you’re right, the end date should be 2/28 — I’ve corrected it and re-sent your lease,” but only once a human on our side has approved that specific write.
Phase 2 — make Clara own the stage (tickets, ordered)
- Applicant status visibility: stage/approvedAt/unit/lease dates in Clara’s context + a
get_application_next_stepstool; retire the “leasing team will reach out” punt. - Knowledge schema:
securityDepositper unit type; structured concessions (eligibleTermMonths, newLeasesOnly, mechanics, repayment);applicationPolicy/moveInPolicyblocks mirroring renewalPolicy/turnoverPolicy + settings UI accordion. - Applicant-acknowledgment message class — narrowed by decisions C and B. No Clara approval announcement (C: AppFolio’s notification stays the announcement). What remains is answering the applicant once they come back — deposit amount by unit type, prorated first payment, e-sign expectations. The unsigned-lease reminder cadence is decided (+24h/+48h/+72h) but deferred out of this round per B.
- Lifecycle stages between approved and lease_signed (lease_sent, out_for_signature, move_in_scheduled) + a PM reminder kind for “approved, no lease sent” (SLA: same-day) + review-queue lane.
- Lease-date auditor in production: run
auditLeaseDates+ proration checks against every new/changed pending lease (would have caught Hayley’s 1/31 and the $613 unit-615 under-bill); alert on discrepancy. - Move-in coordination: key pickup, buzz code, what-to-bring, utilities/renters-insurance — the “ask for Erika, she’s expecting you!” experience (dossier #7) as the standard, driven by the
moveInPolicyblock. - Escalation reliability: renewal_escalate tool failure alarms (Ekene’s failed silently); no-pickup real-time detection (Twilio statusCallback + AMD).
- E-sign watching: surface AppFolio e-sign state (tenant signed / awaiting countersign ≤72h per the 7/16 decision), chase unsigned leases on our cadence.
Decisions — final record (2026-08-05)
All five decided by Fede on 2026-08-05. These are locked, not options. Two of them (B and half of D) were decided and deliberately deferred — the answer exists, the build does not, and that is on purpose.
A. Free month on a 6-month lease
The free month only comes with a one-year lease. If someone asks for it on a six-month lease, Clara says no and shows them the one-year deal instead — she doesn’t send it to a person, and she doesn’t invent a smaller discount. This is the exact question Hayley asked on 7/18 and never got an answer to.
B. Unsigned-lease chase cadence
We know how often we’ll remind someone who hasn’t signed: a nudge the next day, another the day after, then a manager gets pulled in on day three. But we’re not building the reminders yet — first Clara has to be able to answer the questions applicants are already asking. Until then, nobody is chased automatically.
C. Who announces approval
The applicant already gets a message from AppFolio saying they were approved. We are not adding a second “you’re approved!” message from Clara on top of it. Clara’s job starts at the next question — what do I pay, when do I sign, when do I move in.
D. Transfer no-pickup
connected. No SMS back to the caller, no PM chase, no un-resolving the conversation — both were explicitly deferred by owner decision on 2026-08-05.What drove it (verified): a real vendor voicemail left zero footprint anywhere — the box it landed in is unmonitored, so nothing and nobody was ever going to act on it. That killed the black-box assumption we had been reasoning from: these calls were not landing somewhere we couldn’t see, they were landing nowhere. Labelling them truthfully is the fix that is worth having today; automated chasing is a separate decision for later.
When a call is handed to a person and nobody picks up, we will stop calling that a connected call. That’s all we’re changing right now — the caller does not get a text back and no manager gets an automatic task. We checked one real case end to end: a vendor left a voicemail and it reached literally no one, because the mailbox nobody listens to was the destination. So the honest record comes first; deciding who chases comes after.
E. Concession repayment on early termination
If a resident got a month free and moves out early, do they owe it back? We are not settling that in the abstract. If it’s written into a property’s policy, Clara reads it out. If it isn’t, she hands it to a person and says so — she does not make up an answer that sounds reasonable. Making up a reasonable-sounding answer is the single failure this whole document exists to stop.
6. Test harness (how we keep it honest)
Real transcripts (anonymized) + synthetic variants; deterministic graders for every dollar/date; LLM judge for tone/no-fabrication (any invented approval/exception = automatic fail — the Ekene rule); Willows for all write-path tests; harness runs on the subscription (never metered keys); merge-gating per repo convention. New bad interactions get added as cases the day they happen.