One person, several homes

One renter asking about several homes should get one conversation, not several. What we decided, where each piece stands, and what ships next.

Rewritten 10/9, midday (Fede: must-haves only) · Updated 10/11: the follow-up restart is decided and in the merge queue · Decided · shipping · Sources: Jay Taylor’s three emails (Western Slope, 10/8) and sections 27 and 53 of the leasing-engine design page.

Oct 29 follow-up: The prospect record across homes: audit of all 118 real tour cards, the per-home facts hole and lead-source bugs, with decisions D1 to D3.

Contents

  1. The short version
  2. Where it stands
  3. How it works
  4. Retro 10/10: the first same-moment case
  5. Why a separate first-reply path exists (history, 10/10)
  6. Redesign 10/10: one follow-up track per person, restarted by a new home
  7. What’s next
  8. Open for Fede
  9. Appendix: evidence

The short version

The problem. At Western Slope, one renter asking about several homes got several of everything: duplicate AppFolio cards, split conversation threads, and doubled follow-up texts.

The decision. One person = one conversation = one follow-up clock. A home is a fact inside that thread, never a second thread. A second home that arrives while that clock still owes a message restarts it from the top, anchored at the new home (Fede, 10/10: “Build it and ship”). No switches: these are fixes to live behavior and go live everywhere on merge.

Ship order. Match listing-site leads to the person we know (done). Stop the stray second inquiry (done). One conversation per person and the repair of the 10 split people (done 10/9). Then one follow-up clock per person, then the “which home?” question and the application to the chosen home.

The full page

Where it stands

Must-haveStatusProof or date
A listing-site lead with no phone or email is matched to the person we already knowdoneLive 10/8, PR #18085. Tested on 9,987 real cards: 827 right joins, 7 doubtful.
A second home no longer creates a stray inquiry or a reply on the wrong addressdoneLive 10/9, PR #18112.
One conversation per person across all their homesdoneMerged 10/9, 2:25 PM (PR #18286), live everywhere, no switch. Proof: every customer’s book replayed unchanged, Camellia model inputs byte-identical 22/22, Willows and Fairhaven live runs, four planted defects red; review found two real bugs in the stop rule, fixed before merge.
Repair the 10 Western Slope people already split across threadsdone10/9, 12:30 PM. 5 people folded to one written thread each, messages in date order, one live duplicate follow-up stopped; the other 5 only had calls, which stay as separate records by design.
One follow-up clock per person that knows every homedoneMerged 10/9, 4:05 PM (PR #18305), live everywhere, no switch. One message names every home. Proof: 1,703 inquiries replayed, one-home prompts 3,308 with 0 differences; Willows and Fairhaven live runs; review found one real gap (a second home inheriting an empty schedule), fixed before merge.
A second home restarts the person’s one follow-up trackmerged, live everywhereFede ruled restart 10/11. PR #18673 (the restart) and PR #18674 (fallback text names every home) merged 10/11 and were in production before 11 AM; the harness and replay code merged as #18812, #18676 and #18823; the follow-up wording fix (#18827, every follow-up names each home the person asked about) and the gone-home hand-off (#18831) merged 10/11 afternoon. No switch. Proof: unit 17/17 with a planted defect red; 9,443 real people replayed before and after (peak clocks owing a message per person 5 → 1; people with two clocks 913 → 0; 40,449 messages both sides; 1,082 restarts for 913 people; one-home people byte-identical); the real workflow replayed with 0 faults. Willows live run: right after deploy.
The “which home?” question, plus the other reply-writing improvementsdoneShipped 10/9 (PR #18351) as "Clara knows every home's state"; the narrowing question itself stayed out (12% in replay against a 70% bar). Replay: 97 of 115 multi-home steps pass (51 on the old code); one-home prompts 1,275 of 1,275 identical.
The application goes to the home the renter chosedoneMerged 10/9 (PR #18351). The application goes to the home the renter named in the message Clara is answering; two homes named means she asks. Replay 18 of 18.
Clean up duplicate AppFolio cardsdone7 Western Slope duplicate cards marked Inactive, reason Duplicate, history kept (Bow’s second card included); AppFolio Merge not used (needs their Leasing CRM). Jay’s own test card 236 not yet confirmed.
Inactive, Cold or Waitlist on one home, with a reasonnot buildingFede, 10/9.
New screens or panels before the behavior is provennot buildingFede, 10/9.

How it works

One personmatched by phone, email, or (listing-site leads) exact name within 7 days
→
One threadevery email, text and call, whatever home it is about
→
Homes are facts2980 Emerald: open, toured
2978 Emerald: open
363 Ember Ln: rented
→
One follow-up clockwakes Clara with every home; a tour or reply on any home counts for all
→
One applicationto the home the renter chose
The model. Everything about one renter runs through one thread and one clock. Homes are details inside it, never separate conversations.

Clara keeps one record and one conversation per person. A second home is a new turn in the running thread (“You also asked about Oak St. It’s open; want to see it with Elm on Saturday?”), never a second first email. Most second homes arrive days later, so this turn is the normal case, not the edge.

Follow-ups are wakes, not timers, as on the vision page: when the clock fires or a new home arrives, Clara is woken with the whole picture and writes the next message, or waits.

The job is to narrow to one: answer about every home, ask one question that splits the set, get at least one tour (several are fine), then send the application for the home they chose.

The model is ours, not AppFolio’s: Clara’s records hold the state and each property system is a mapping, so it works with any PMS and any lead source.

Retro 10/10: the first same-moment case

What happened

Saturday 10/10, 12:49 PM MT, Western Slope. Clayton Barnfield’s Rent.com card arrived in AppFolio with two homes: 2841 Morningside Ct and 2978 Emerald Cir. Clara made one person and one conversation, as designed. But she sent two first emails 55 seconds apart (12:51:48 and 12:52:43). The second opened “good to hear from you again” and offered different tour times.

Two follow-up clocks started; they fold into one at the first wake, as designed. Nothing went unanswered. Fede: “the first time we get two interests it breaks.”

Why the design missed it

The design assumed the second home arrives days later (“most second homes arrive days later, so this turn is the normal case”). The number that would have tested that was asked for on 10/9 and not delivered until 10/10.

When the second home arrivesWestern Slope (259)Situs (956)All (1,215)
same minute2%10%8%
1–10 min6%13%11%
10–60 min3%4%4%
1–24 h8%16%15%
1–7 days27%25%26%
over 7 days54%31%36%

Gap from the first home’s inquiry to the second home’s, by AppFolio Received minute, same 9,443-person history. Within ten minutes it is the same AppFolio card 148 of 237 times.

Reading: the right bet for Western Slope’s scattered homes, the wrong one for a centralized company like Situs, where one in four second homes lands within ten minutes. There, same-moment is the normal shape, not the edge.

Why the harness missed it

The replays (1,703 inquiries) and live runs graded what Clara says, how many people and cards she makes, and the follow-up clock. No test case had two homes arriving together on one card, and no check said “one outbound per person per arrival.” The first email’s content was right (it named both homes); the count was never checked.

Where Clara still speaks per home

#Path that messages a prospectFires once perAlready-spoke check
1First email on a new card or new homeinquirynone across homes (the cause)
2AppFolio “New Lead” notice, engineinquiryskip if the conversation has messages
3Notice, genericmessage30-min first-touch claim
4Text replymessage in the person’s threadper message
5Email replymessage in the person’s threadper message
6Follow-up texts and emailsinquiry clock, folds to one per person at first wake (Fede 10/10: not acceptable; one per person from the start)12-hour per-person cooldown
7Re-engagementarmed once per person12-hour cooldown
8Tour texts and reminderstourper tour (correct)
9Application linkstour, or person + homeper tour / per person per home (correct)
10Post-tour chasetour12-hour cooldown

“Isn’t it the same Clara?” No. The first reply fires per home from a lead event. When a second home arrives as its own event, that reply is written by a separate first-email writer, not the engine that writes every later reply. The context is the same (every home); the trigger, and sometimes the writer, are not.

No existing rule would have stopped email 2: the 12-hour cooldown covers only timed paths, the first-touch claim only blocks the other path, the “already answered” check is same-home only, and duplicate protection is per inquiry.

How Clara decides to speak to a prospect today
Figure: the first reply is a separate, per-home path; everything after runs through one loop per person. Fede, 10/10: is there a separate first-reply logic, and why?

Name rule, checked

Bow (10/8, 3:55 PM) and Anna Neil (10/3) were not auto-joined because both arrived before the rule merged (10/8, 8:17 PM); replayed, it would have joined both. The rule fires only on a new listing-site email lead, never on card sync, and never revisits existing records, so Anna stays split until a merge rule exists. Not a bug.

Fede’s ruling, 10/10 (supersedes the proposal above)

“If someone inquires about a home we do want to reply within 30 seconds. If that person submits another inquiry it should be the same person, same conversation; it’s fine to do another email, ‘you’re also interested in this.’ Clara knows there are two homes, the follow-ups know there are two homes, but there is one per person. That was the whole point. The hard-coded 12-hour thing makes no sense. Back to the test harness, extend it with this use case, try again. This is a failure.”
Inquiry on home Areply in seconds
→
Inquiry on home B minutes latersame person, same thread, short “you also asked about B” email
→
ONE follow-up track per personnames every home
→
One applicationto the chosen home

Order:

  1. Extend the multi-home harness with Clayton’s real case (two inquiries on one card seconds apart): assert one person, one conversation, at most one first email per home, and exactly one follow-up track per person that names both homes, with a planted control; must be RED on today’s code.
  2. Redesign the follow-up clock to be per person, reviewed by Fede.
  3. Build.

Status: harness extended and RED on today’s code (10/10 afternoon, branch fede/multihome-harness-same-moment, npm run harness:person-first, case 10). Red check: right after the second home arrives, the person has two follow-up clocks instead of one, for about a day until one folds into the other. Green on today’s code: one conversation, at most one first email per home, one follow-up per touch naming both homes after the first wake. Correction: the 12-hour cooldown is not what blocks the second follow-up; the fold at first wake is, and the harness shows the same output with the cooldown at zero. Finding: the 10/9 PRs (#18286, #18305) were proven with unit tests and one-off replays, not a committed harness; this case is now the first committed one. Redesign build in progress on a local branch; no PR until Fede reviews before/after.

Day-two check, 10/11, 12:52 PM: the renter got exactly one follow-up. Both per-inquiry clocks woke within a minute; the home A clock sent one text and the home B clock saw it and closed. So the fold held in production. The wording is the weak spot: the text said “that home is no longer available” without naming which of the two, offered home A plus a third home the renter never asked about, and went by text although the whole conversation had been email. This is the live example for Fede’s question about follow-ups being shaped around one home; the redesign’s follow-up text must name every home the person asked about by name.

Hard-coded windows on the follow-up path (none approved by Fede)

WindowValueHarness exercises it
Per-person cooldown12 hyes
Follow-up touches24 h / 48 h / 7 d / 14 dyes
Min gap between sends20 hno
Final reply grace48 hno
Other home still named30 dyes
Stale clock cutoff / clock lifetime33 dpartly
Lead first-touch claim30 minno
Quiet hours8:00–21:00 property timeno
Quiet-hours hold cap25 hno
Held touch min wait1 hno
First-email consumer claims90 s to 30 d (six values)no
Historical lead min age3 dno

Why a separate first-reply path exists (history, 10/10)

Short answer: yes, Clara still has a separate first-email path. Since 9/24 the regular engine writes the words for most first emails, but about 13,000 lines across 13 modules still run only around the first email, and the old 4,100-line writer still writes the whole email in three cases: a second or third home on the same card (118 of 908 Western Slope cards), a redraft when the planned tour time is gone, and every draft at a company that is not live.

What is separate today

ConcernFirst emailRegular reply loop
TriggerNew-lead event from AppFolio sync or a listing-site emailAn inbound message
One-per-lead guardOwn record per inquiry, event lock, 30-min first-touch claimThe conversation itself
Review holdOwn hold call, before any conversation existsShared prospect-email sender
SendingLow-level sender directly; shares only the templateShared prospect-email sender
BookingPlanned at draft, booked at release, cancelled if never sentBooking tool during the turn
ChecksFact trace, draft checks, auto-rewrite, body check, turn wrapperShared safety checks
AppFolio“Email Sent” record + assign ClaraNo AppFolio note
Who gets an answerSystem-created cards onlyEveryone who writes in
PromptExtra 6-clause “first touch” blockShared email rules

How it came to be

DateWhatWhy
9/18–19First-email record, prep, send and review hold builtWestern Slope launch dark and reviewable; composing through the inbound pipeline left a visible empty “ghost” conversation on every held card
9/18–19System-cards-only ruleFede: “lets just make it so we only reply to system guest cards”
9/20Wired to the new-lead eventFede: “We should not be coupling AppFolio at all with the core agent loop”
9/20–21Fede objects to the split“there should not be multiple reply paths”; “it's insane that we keep building separate things that have issues”
9/24Per-inquiry first emails built on the old writer; engine allowed to write behind a per-property switchFede: “it doesn't matter if it's the first response or a second. Why is it not using the exact same thing?” Per-inquiry stayed on the old writer because the engine answers about the card's own home only
9/24“Retire the composer” PR merged to the integration branch only, never main—
9/29Engine made the only writer; switch deleted; redraft and per-inquiry left behind as “follow-up work” (issue since closed, code still has the exception)—
9/30Listing-site email leads routed through the same pipelineFede: “one engine period”

No PR gives a design reason for keeping per-inquiry on the old writer beyond “the engine turn doesn't do it yet.”

Bugs on the first-reply path since 9/19

DateWhat went wrongWould a normal engine turn have had it?
9/19“Call the office” instead of tour timesNo
9/20“Clara responded” never setNo
9/20Draft crashed, card died silentlyNo
9/21Plain-text email, no brandingNo
9/21No email because the person record did not exist yetYes
9/20–21Every Western Slope system card skippedYes
9/21“Pencil you in”, wrong timesNo
9/22Generic “variety of homes” on 23 of 32 cardsPartly
9/23Second and third inquiries never answeredYes (trigger design)
9/23No tour times when no unit namedNo, engine later hit it too
9/23Double greeting, specs recited, tour for a gone homeMostly no
9/26–28Prep stuck, time-budget timeoutsNo
9/29Unsized cards lost tour timesYes
10/1One lead answered twice, once per pathNo
10/2–5Cold first email to someone who already toured, applied or was mid-conversationMostly no
10/7Returning renter pushed into a tourPartly
10/9Tour offers started tomorrow, skipping todayYes, every channel
10/10Two first emails 55 s apart, second said “again”No

Score: 11 of 18 would not have existed as a normal engine turn, 4 would have happened anyway, 3 partly. “Didn't offer a tour the next day” is a recurring symptom, not one incident: it hit the old writer (9/19, 9/23), the engine (9/29) and the shared slot finder (10/9).

What is truly first-reply-specific and must survive a fold: exactly one first email per person (today per inquiry); the system-cards-only guard; hold-or-send decided before any conversation or tour exists; book at release and cancel if never sent; the AppFolio “Email Sent” record and assigning Clara; never cold-email someone who already applied, toured or was answered; tell the team when drafting fails. The prompt rules (greeting, one sentence on a system card, the card's home wins, listing price only, never volunteer a gap, book a requested open time) already live on the engine.

Recommendation (Fede already ruled “one engine” on 9/24 and 9/30; the question is what is left to fold): 1) move per-inquiry and the no-tour redraft onto the engine and delete the old writer, which needs the engine thread to see every home on the person's card; 2) send the first email through the shared prospect-email sender so hold and branding come from one place; 3) have the AppFolio note and the engaged stamp listen to the “Clara replied” event. Structural risk: today the engine turn creates a conversation and books before the hold verdict, and the prep step undoes it; the 9/26–28 timeouts were cleanup failures of this kind. The real fold puts hold, checks and the one-per-person decision inside the engine's own send step.

Redesign 10/10: one follow-up track per person, restarted by a new home

Before: each home started its own follow-up clock; they merged a day later. After: the first home starts the person’s clock. A later home that arrives while that clock still owes a message restarts it from the top: the old clock stops, one new clock starts anchored at the new home, and the next follow-up is Day 1 after the new home’s first reply, naming every home. First replies are untouched: each home still gets its own reply in seconds (“you’d also asked about…”). No settle window, no switch.

Why restart rather than join: follow-ups sent 1–2 days after the person last wrote get a reply about 30% of the time; at 3–14 days it is about 7%. A new home is the person writing again, so the clock should count from there.

A home arrivesits own first reply goes out Read the person’s track rowone row per person; first writer wins Clock running and still owes a messageRESTART: stop it; start one clock at the new home No live clock (first home, or it ended)START one clock; the row points at it WHEN TWO PERSON RECORDS MERGE The merge moves home rowsto the survivor; ids never change The clock finds its homeseach wake re-reads the person’s rows A leftover second clockfolds at its first wake (kept backstop)
The rule in one sentence: the person’s track is the single running clock named by their track row; a new home moves that row to itself, stops the old clock and starts one from the top, and a merge moves rows (never ids), so the clock follows its rows.

Restart, not “start a second clock and fold it later”. The track row is moved to the new home before anything is stopped (one row per person, first writer wins), then the old clock’s run is terminated with the reason “restarted: the person asked about another home” and its row is stamped done the same way the 10/9 fold stamps a folded home, so the old home is still named in every follow-up. Three cases do not restart: two homes in the same moment (the row is claimed but no clock is enrolled yet) join one clock; a repair of a dead clock joins the live one instead of killing it; a clock already in its final 48-hour reply wait is left alone and the new home starts fresh. The old fold stays only as a backstop.

Hard-coded windows: what still matters

WindowRole now
12-hour quiet gap between Clara’s messagesnot needed for one clock Proven with it off. Still skips a touch right after a reply (example 2).
20-hour minimum gap between touchesspacing only
48-hour wait for a last replyunchanged a new home then starts fresh
30 days: which homes a follow-up namesreal Decides content, not count.
33-day clock lifetime, quiet hoursunchanged

Do follow-ups name every home?

The AI draft and the email subject already named every home. The fixed fallback text (used when a draft fails its checks) named one. Fixed:

Before (fallback)

Hi [name], it’s Clara with Home A following up on your inquiry. Would you like to set up a time to take a look?

After (fallback)

Hi [name], it’s Clara with Home A following up on the homes you asked about, Home A and Home B. Would you like to set up a time to take a look?

Email and Spanish fallbacks changed the same way. Still one-home: “Clara with Home A” and per-home branding.

Every real person replayed, before vs after

9,443 real people (Western Slope + Situs history)BeforeAfter
One-home people with an identical follow-up trace8,228 of 8,228 (byte-identical)
Multi-home people with 2+ clocks owing a message at once913 of 1,2150
Most clocks owing a message for one person at once51
Follow-up messages, all people40,44940,449
Restarts—1,082 (913 people)

Real arrivals, the real start/restart code, a simulated clock, nothing sent. The count of messages does not change; their timing does: every follow-up now lands 1, 2, 7 and 14 days after the person last wrote, and names every home. The real workflow was then replayed on a time-skipping server over the same people (200 multi-home people: 0 faults, at most one owing clock per person, 154 restarts, 1,392 messages, matching the simulation).

Three real renters (scrubbed)

1. Two homes 2 minutes apart: before

Day 0: reply on Home A, then reply on Home B (“you’d also asked about Home A”). Two clocks run for a day, then fold. 4 follow-ups (Days 1, 2, 7, 14); fallback names one home.

After (by the rule)

Same replies. B restarts the clock from its own reply, minutes later: the same 4 follow-ups, each naming both homes.

2. Second home 19 hours later: before

Home B’s reply starts a second clock; A’s folds 4 hours later. B’s clock restarts: 4 follow-ups (Days 2, 3, 8, 15).

After (by the rule)

A’s clock stops before its first touch; B’s reply starts the one clock. 4 follow-ups at Days 1, 2, 7, 14 after B’s reply, each naming both homes.

3. Second home 2 days later: before

Days 1 and 2, B’s reply, then B’s new clock: Days 3, 4, 9, 16. 6 follow-ups, 4 days in a row.

After (by the rule)

Days 1 and 2 on A, B’s reply, then the clock restarts: Days 1, 2, 7, 14 after B’s reply, each naming both homes. Same count as before; each one now lands 1–2 days after the person last wrote, which is where replies come from.

Proof, rollout, risks

RungResult
Unit tests, planted defect17 of 17 planted “always start” goes red
Same-moment harness (the 10/10 case, case 10)red → green one track after each arrival 1,1; after the first wake 1; names every home; one-home control identical; the “hide the running clock” mutation goes red
Full replay of real peoplepass above
Real workflow replay (time-skipping server)0 faults case 10: A terminated as “restarted”, B sends all 4 follow-ups naming both; 200 multi-home people, at most one owing clock each
Mergemerged PR #18673 and #18674 merged 10/11 (in production before 11 AM); harness and replay code merged as #18812, #18676, #18823; wording fix #18827 and gone-home hand-off #18831 merged 10/11 afternoon
Willows live run, then sandbox companynext right after deploy: one registered tester asks about a second Willows home while a clock runs; expect the old clock terminated as “restarted”, one clock on the new home, Day 1 naming both

Running clocks drain as today: two still fold at their first wake, no double send.

Risks: two homes arriving in the same moment through two different consumers can still start two clocks, because the sibling list is read eventually-consistent (the fold catches it at the first wake; tracked as issue #18678); if the new clock fails to start after the old one was stopped, the daily repair job re-enrols the home; AI-written follow-ups were not regenerated (examples show fallback text).

Willows production run, 10/11

Setup. Sandbox company only: Home A = the Willows (guest card by the robot), Homes B and C = Yale 25 Station sandbox (Zillow-style lead email into its leasing inbox). Three test renters on our own test mailbox. No timer shortened; the reset is proven from the workflow history. Production was on commit 26f84cf686 (includes #18673).

Why C is a second renter. A property keeps one inquiry per renter, so a renter cannot ask about two Yale homes as two clocks. “Third home while the clock runs” is therefore Renter 1: Willows clock running, then Yale 3.5 minutes later.

RenterWhat happened (UTC)Clock result
Renter 2: A + B at the same momentWillows card 19:52:29, Yale email 19:53:14. Yale engaged first (19:54:10, run 01a12c87-abcf). Willows engaged 38 s later.restart Yale run terminated 19:54:48.597, reason “restarted: the person asked about another home”. New Willows run 01a12c88-3deb started 19:54:48.683, first wait 86,399 s (next wake 10/12 19:54:48). One running clock.
Renter 1: C while the clock runsWillows anchored 19:54:12, run 01a12c87-b13e running. Yale email 19:56:42; Yale engaged and anchored 19:57:34.538.reset Willows run terminated 19:57:34.909, same reason. New Yale run 01a12c8a-c7a1 started 19:57:35.01, anchor 19:57:34.538, touch 0, first wait 86,399.5 s, so next wake 10/12 19:57:34.8 = day 1 from the Yale first email. One running clock.
Renter 3: one-home controlWillows card 19:52:37, anchored 19:55:37.unchanged One run 01a12c88-fb57, day-1 wait, no track row (one-home renters never write one).

Day-1 wording check, 10/12

RenterDay-1 wakeWhy nothing was sent
Renter 1 (Yale holds the clock)19:57:35, skipped no-mailbox, retries at +1 h, +2 h, +3 h, then the schedule moves onThe Yale sandbox home has no Microsoft mailbox (no property mailbox, no company mailbox on the sandbox org). The first reply went out through the no-mailbox SendGrid sender; the follow-up sender is Microsoft-only. Sandbox setup gap, plus a two-senders mismatch filed as an issue.
Renter 2 (Willows holds)19:54:49, stopped closedThe 10/11 run marked its own guest card Inactive at 20:01 UTC as cleanup; the sync turned that into a closed inquiry, and a closed home never gets a follow-up. Correct behavior; the test killed its own proof.
Renter 3 (one-home control)19:55:37, stopped closedSame cleanup.

Re-run started 10/12, 2:24 PM MT. One new renter, Yale email first (20:24:14), Willows guest card 214 second (engaged 20:26:00). One conversation, Willows holds the one clock, day-1 wake 10/13 20:26 UTC (2:26 PM MT), sent from the Willows mailbox. Nothing is closed until that text is read. Expected: the text names The Willows and Yale 25 Station and no other home.

Harness lesson: never close or mark inactive a test card before the last proof rung has fired; closing is correct engine behavior and ends the clock.

Why restart and not join for Renter 2. Join only happens when the first home has claimed the clock but not started it yet. Yale’s clock was already running 38 s before the Willows home engaged, so #18673 restarts. That is the intended rule.

Track row (one per renter)BeforeAfter
Renter 1none (one home)holder = Yale inquiry b3fa965b, claimed 19:57:34.765
Renter 2noneholder = Willows inquiry f77da55d, claimed 19:54:48.343 (Yale held it for 38 s)
Renter 3nonenone
Emails the renters gotConversations
Renter 1: Willows first email 19:54:12; Yale first email 19:57:37 (“You’d also asked about The Willows”)1 both homes in one thread
Renter 2: Yale first email 19:54:14 (“You’d also mentioned The Willows”); Willows first email 19:54:482 one per home
Renter 3: Willows first email 19:55:371

One first email per home in every case. No texts: the test phones are fictional 555 numbers.

Finding, outside the clock change: when two homes arrive within a minute, each opens its own conversation, so the renter gets two threads. The clock is still single. Follow-up candidate for the conversation-joining code, not a #18673 defect.

Cleanup. Willows cards 209, 210, 211 marked Inactive (reason Duplicate) by the robot at 20:01; Yale has no AppFolio cards. The three test clocks are left running and will send their day-1 follow-ups to our own test mailbox around 19:55 UTC on 10/12. The older stray clock from the 10/8 test (person 2727b016) is also still running, untouched. All writes are in the production write ledger.

What’s next

Every step climbs the testing ladder: replay of every customer’s real book, byte-identical where nothing should change → Willows live run → Fairhaven sandbox.

  1. PR 1, one conversation per person (today). Proof: full replay with one-home cases byte-identical, then Willows, then Fairhaven.
  2. Task 2, repair the 10 split Western Slope people (done 10/9). Proof: each surviving thread’s message count equals the sum of its parts, and the Bowmuxlow and Tessa Adams pages read in date order.
  3. PR 2, one follow-up clock per person. Proof: replay shows one nudge per person, never one per home, then Willows and Fairhaven.
  4. PR 3, the “which home?” question and the application to the chosen home. Proof: the narrowing question well above 20 of 50 on the replay, one-home cases unchanged, then Willows and Fairhaven.
  5. Task 3, duplicate AppFolio cards (later). Proof: a dry-run list of every card to touch before any write; we do it, never Western Slope’s staff.
  6. No-show marked in AppFolio (from Jay, 10/9). Done 10/11 (PR #18697): a staff-recorded no-show now flips the AppFolio showing to No Show. Before: staff tells Clara “he didn’t show”, Clara stamps the tour as a no-show in PropFlow and writes the card note, and the AppFolio showing stays Completed. Design: the same staff reply also flips the AppFolio showing to No Show through the robot (the robot’s cancel-showing action already takes a no-show status, but AppFolio rejected its guessed value on 10/9; the real action must be captured first). No switch; a fix to live behavior. Proof: Willows showing #10 on test card 107.

Open for Fede

  1. Merge on Western Slope cards: does AppFolio’s action menu show Merge on one of their cards? Recommend: check one card; if not, Mark Inactive plus a note.
  2. Jay’s card 236: Mark Inactive by hand now, or wait for a robot action? Recommend: the robot action later, with the card cleanup.
  3. New home mid-follow-up: Decided 10/11: restart. Restart from the top, anchored at the new home (Fede: “Build it and ship”). Shipping as PR #18673. See the redesign.
  4. Staff on the phone line: handed to the vision page. Recommend: keep it there, out of this work.

Appendix: evidence

Tables behind every number above

Name rule, tested on every card we hold (10/9)

WindowRight joinsJoined to a different contactTypo on the contactUnknown
3 days661539
7 days (shipped)8277312
14 days9359314
30 days1,00312719

9,987 cards, all customers, all years. The 7 doubtful joins are old Situs cards from 2022–2023.

Replays of real Western Slope leads

ReplayWithout the fixWith the fixWrong joins
42 email leads, 9/29–10/8: new people16100
Same: new AppFolio cards16100
Same: home added to an existing card13190
61 email leads since 9/15: new cards22170

Same-name collisions (2,993 cards, 2025 on)

RuleReal duplicates fixedStrangers merged
Before: same home only05
Any home, 30 days563
Any home, 14 days, fake names blocked522
Any home, 7 days, fake names blocked, two same-name people = no match (shipped)480
30 days without the two-match guard586

Reply prototype (10/9, offline, 57 masked people)

MomentTodayPrototype
First email0 of 99 of 9
Later home mid-thread3 of 4139 of 41
Follow-up wake0 of 126 of 12
Text reply4 of 97 of 9
After tour22 of 2222 of 22
Asks one narrowing question0 of 5120 of 50
One-home control steps unchanged22 of 22 byte-identical

Dataset (full AppFolio history)

FactNumber
Western Slope older cards opened by the read-only robot pass1,703
Western Slope cards with a full activity log40% → 95%
Who added the extra home (Western Slope)renter 29% · staff 30% · application under 1% · unknown 41%
Homes per person, all customers (9,443 people)one 87% · two 10% · three or more 3%
Second home arrives the same dayWestern Slope 16% · Situs 37%
Applications per personalways one home

Industry (research 10/8)

QuestionWhat the market does
One record per person, one per property under it?Yes: AppFolio, Entrata, Funnel, Knock, EliseAI. Older one-card-per-property survives in Yardi Voyager.
Where status and source liveOn the per-property record, not the person.
DuplicatesMatched on phone or email, merged by hand. Nobody documents listing-site relay addresses.
Several homesVendors cross-sell when the first home does not fit; none documents narrowing a set the renter brought.

Not built, by ruling

Not builtRuling
Closing one home with a reason in AppFolio (Inactive, Cold, Waitlist)Fede, 10/9
Any new screen before the behavior is provenFede, 10/9
A switch or setting on any of thisFede, 9/30 and 10/9
A “possible duplicate, merge?” button or queueFede, 9/8
A timer that waits for more homes before replyingSection 53
Handing cleanup to the client’s staffFede, 9/30
PropFlow Docs