Clara joins mid-flow

One page for how Clara steps into leasing work that is already in motion at Situs: showings staff book by hand in AppFolio, tours the prospect must confirm or lose, and the external updates (moves, cancels, reassignments, silence) Clara has to notice before she acts. It holds the designs, the real-record evidence, and the decisions still open.

Started 2026-11-02, updated 2026-11-05 · Proposed — pending Fede's review · internal only, nothing here is built or turned on · sections link as #found-2026-11-02, #external-updates-2026-11

Clara joins mid-flow

Clara as a coworker who can step into a renter's journey at any point: a showing staff booked by hand, a lead a person answered first, a tour that already happened. Two full designs on one brief, Fable 5.1 and Opus 5.5 at max, so the pick is made once.

Proposed, pending Fede's review · Nov 2, 2026, Norma section, one-pager and one-page tour design added Nov 4 · read-only research, nothing sent, no PR · sub-designs on this page: staff-booked showings, confirm or cancel · related: staff tour moves · AppFolio switch list: Situs ramp-up changes

Tours: one design, whoever booked them (Nov 4, proposed)

Added Nov 4, 2026 · Shipped Nov 5: #25337 (every tour step reads the thread first) and #25330 (Clara runs the steps on showings staff book; active only once onboarding records the customer's PMS no longer texts renters about showings) are merged. Live proof at Fairhaven is blocked until the test-company model accounts reset (~Nov 10).

Clara handles every tour, whoever booked it, and never repeats what the renter already got Clara handles every tour, whoever booked it, and never repeats what the renter already got A showing gets booked One record Tour steps Before every send: read the thread Clara books it text, email, call A teammate books it in AppFolio One tour record in Clara origin: Clara | human staff-booked showings are read from AppFolio every few minutes (new) Confirmation Day-before reminder 1-hour reminder Lockbox code After-tour"how was it" Follow-ups ifthey go quiet 1Did a teammatealready say it? 2Did AppFolio's automatictext already say it? 3Did Claraalready say it? Any yes skip, note it on the tour All no send Onboarding: customer turns AppFolio's automatic showing texts OFF (one voice) Company setting, default off: Clara messages renters on staff-booked tours (Fede turns on per customer) gates only this path

What changes

PieceTodayAfterSwitch
Staff-booked showingsinvisible to Claraone tour record, origin humannone (a fix)
Clara's own tour messagessent blind; only the after-tour link checks for a copyevery step reads the thread first, skips what was already receivednone (a fix)
Messages on staff-booked toursnonesame steps as her own tours, read-firstnone (a fix). Runs once onboarding records that the customer's PMS no longer texts renters about showings; default: still texting, so nothing changes at any customer on merge

Results of the local test (Nov 4)

Real threads replayed locally, no sends: 27 tours from Situs and Western Slope, 89 tour steps, each judged against the thread as it looked at send time. Labels were written by hand before the model ran.

At send timeAfter a 5-minute wait
Right call (agrees with the hand label)72 of 89 (81%)76 of 89 (85%)
Duplicate would have gone out1410
Needed message would have been skipped33
Skip only visible after the wait–27 (25 are booking confirmations; AppFolio's text lands 1–2 min after the office books)

Staff guest-card notes: live and read by Clara (Nov 5)

Fede, Nov 5: 'we need to be able to use notes', 'no feature flags', 'battle test it'. The Sep 30 notes import (dark for five weeks) is now live everywhere (#25404). Notes re-import within a minute of a change (#25413). Clara's follow-up, first-reply and tour-step reads consult the notes through the model, classifying each as a person acting, a bookkeeping note, or Clara's own. The first cut (a presence check) was rejected by its own battle test.

CheckRule-based cutModel read
Wrong holds on live-possible cases7 of 25 (28%)0 of 13
Follow-ups held, Situs / Western Slope (30 days)1–15 / 10–305 of 45 / 19 of 119
Planted bookkeeping note held / planted teammate call heldn/a0 of 24 / 24 of 24
Note text leaking into any decision or renter-bound text00 of 653
No card rows: decisions identical305/305, 344/344164/164
  • Planted-defect controls: remove AppFolio's booking text, the model sends (PASS); add a teammate's confirming text, the model skips (PASS).
  • Most remaining misses are definitions, not reading errors: the 1-hour reminder also carries how to get in, so the model sends it even after AppFolio's confirm exchange gave the time (5 of the 13 misses); reworded to time-only, 39 of 40 agree.
  • "A teammate owns this thread" must not gate tour reminders: it was true on 16 of 20 steps on Clara's own tours. A one-hour "teammate texted recently" rule would have silenced 13 needed messages.
  • Limit: this only stops Clara's copy. At Western Slope showing 597, AppFolio's "Thanks for visiting" email came ~22 h after Clara's after-tour link, so the renter got both; only AppFolio's own switch removes that.

Honest number: the read is right 85% of the time, so Clara's steps on a staff-booked tour run only where the PMS's own showing texts are off; otherwise about 1 in 10 renters would get a duplicate.

Harness: branch fede/office-activity-harness, scripts/coworker-harness/office-activity/send-check/ (prompt, fixtures and labels in separate folders; 161 subscription calls). No PR.

Built in three small PRs, in that order. Proof: replay of real Situs and Western Slope threads with AppFolio's texts on, then a live run at Fairhaven. Decision (Fede, Nov 5): no Clara switch ("why is this a setting"). Status: PR 1 read-first gate (#25303), PR 2 steps on staff-booked showings (#25229); results and Willows proof added here when they land.

Nov 4 one-pager: what staff do by hand, what Clara sees, and the path forward

Added Nov 4, 2026 (evening) · Tour-row decision taken Nov 4 evening; three pending · harness part 1 results in · full pass by an Opus 5.5 and a Fable 5.1 reviewer, five live sessions asked, past sessions mined, every page re-read · read-only, no PR · supersedes the Nov 2 decision list and N1–N5: three decisions below · independently verified against main a3cdc6bbeb Nov 4 evening (corrections below)

The problem in one line. Clara decides "is a person already on this?" from the last text in the thread. At Situs the office works in AppFolio, not in texts: a person booked every showing this year, and staff answered first in 36 of 47 text threads. Office silence in the thread means "someone has it", and Clara reads it as "nobody does" (Norma Nov 4, Matthew Nov 2). The opposite failure exists too: one staff text silences her for good (43 of 73 active Situs threads).

A message arrivestext, email, call turn A timer firesTemporal: tour steps, follow-ups, follow-through The office acts in AppFolioshowing, note, call, assignee, status Office-activity recordneutral rows, by adapter (step 1) One read: shouldSpeak"does a person at the office own this? is the renter waiting on anyone?" speak · stay quiet · tell the host · signal the tour or follow-through workflow
Where it sits in the loop. Three ways a turn starts. The one place that decides whether Clara speaks already exists (#22333, #22509) and already returns "stay silent": when a teammate holds the thread, and under seven before-draft rules. The gap is elsewhere: five other places answer "is a person at the office on this?" with their own rules (the wake, the follow-up check, the log-only first-touch check, the unwired assignee check, the send-time hold), and none of them can see the office's own record. The staff-activity record is the missing input; the fix is to hand it to that one door and have the five ask it. A staff action also signals the Temporal workflows that hold the timers (a moved showing re-bases the reminder; a staff reply closes a follow-through item), so timers never fire on stale state.

1. What the office does by hand, and whether Clara sees it

Three questions per action: is it in our records, is it shown in her prompt, does any decision read it. "Yes to records, no to decisions" is the pattern; staff-made showings are the one row that is no on all three.

Staff action in AppFolioIn our recordsIn her promptRead by a decision
Texts the renter from AppFoliolive (1–2 min)yesyes: stops wake, sets the hold (never released)
Emails the renter from AppFoliolive (up to 6 h)yespartly: the follow-up check, and it stops the wake when it is the newest office row; sets no hold
Books, moves or cancels a showingnoonly AppFolio's own notice textno; availability also reads connected host calendars, so where the host's calendar is connected the showing is an unnamed busy block
Marks shown / no-shownonono
Writes a notelive (the card's newest notes, within a minute, no author; the entry-by-entry import with authors is once per card, dark)no for renters; a staff member can ask Clara by text or call and she reads the notes backno; one look reads them, log-only; the classifier has no caller
Logs a calllive (in the card's newest notes, by day, no author; the import with authors is once per card, dark)no for renters; staff can ask Clara and she reads them backno; log-only
Changes the assigneelivenono; the assignee gate is built, never wired
Sends the application linklive (as a mirrored send)yesyes: Clara skips her own link
Marks applied / lostlivestageyes: first email and follow-ups stop
Creates a card by hand (walk-in)liveyesfirst email yes; "hand-made, wait" is log-only; wake never checks it

Showing outcomes (shown / no-show) are out of scope for now by Fede's word (Nov 4): a later phase, not dropped.

The wake reads the whole thread, not texts only. An office call filed on the thread would have kept Clara quiet on Norma; it was filed about 40 minutes late.

Sources: main a717d5d4ea, production settings read Nov 4 (notes import on only at Sandbox). Ten doors decide whether Clara speaks (wake on an AppFolio text, Twilio text, email, first touch, staff email, staff text, reminders, after-tour link, follow-up cadences, voice); none reads a staff showing or note. Out of scope by Fede's word (Nov 4): staff mail in their personal mailboxes.

2. Results so far

What was measuredResultMeaning
Chime-in replay, 42 live Situs prospect texts, 19 threads, Oct 28 to Nov 4 (session 006, numbers)today's sender list right 34 of 42, 1 talk-over · the follow-through read as written 31 of 42, 7 talk-overs · control holds"Has anyone on our side answered?" is the wrong question. The read needs "does a person at the office own this thread right now", with any staff touch, human-made showing or office call as yes. The late office calls and notice-only showings were the two signals it could not see
Norma, Matthew, Deyci: both gates on the Nov 4 caseboth wrong (the office call proving staff had it was filed 40 min after the wake); Oct 30 both quiet, right; Nov 2 today's gate never ranReading the record is not enough on its own: the wake rule fires before any read asks. Read and react are two steps, as Fede put it
Situs shape (Jan to Sep)507 showings, all by a person (383 staff, 124 the shared VA seat); 15 of 111 real staff tour changes handled right; 43 of 73 held threads never releasedThe before numbers for the path below
Office-activity harness, part 1 "read all the data": 48 Situs cards, Oct 21 to Nov 4, 228 staff actions, truth = each card's raw AppFolio Actions Log labelled by a separate model pass, 4 cards and the 5 named cases checked by hand (this lane, local, no PR, replay makes zero network calls)what we already store finds 152 of 228 (67%) and 0 of 27 staff-booked showings · adding the per-card showings read: 181 of 228 (79%), 26 of 27 showings · control: drop the showing source and the Nov 4 case goes red againThe showing read is the single biggest gain. The 47 still missed: 17 mass texts we file as bulk on purpose, 13 messages for 4 people with no thread on our side, 6 cards with no creator or a different created time, 5 outcomes and moves the current-state read cannot see, 6 single rows. Part 2 is the next row
Part 2, "react correctly": the 36 of 42 replay turns that have a part-1 fixture, 3 runs each (session 006, round 2)A today's sender list: 30 of 36 right, 1 talk-over, 3 left waiting · B the read with the office rows visible: 28 right, 7 talk-overs · C the read plus "does a person at the office own this thread right now?": 32 right, 0 talk-overs, 4 left waiting; stable over 3 runs; controls hold (inverted 4, shuffled 25.8)C is the design. Under C: Norma (Nov 4) quiet, and the office called 1.7 min later; Matthew (Nov 2) quiet at the booking notice; Deyci (Oct 30) quiet; Stephany's thread quiet twice where B spoke and staff answered 3.6 and 17 min later. Every "owned: yes" rested on a staff message or a named office person, never on an unauthored row. Caveat: the office rows were visible at action time, the favourable case; production sees them later, so the live number sits between B and C until the showings read (step 1) is live
What the record cannot tell (same run)74 notes and logged calls have no author (some are Clara's own) · no showing names who booked it (the confirmation goes out under the card's assignee; 14 of 26 would be wrong by sender) · 30 "status changes" are mostly the Tenant Turner integration, not a personRows carry "author not recorded", never a named teammate. The read in step 2 treats an unauthored row as office activity, not as a person's word; decision C3 reads facts from notes, never attributes them
Staff action kind (Situs, Oct 21 to Nov 4)Stored data only+ showings read
Showings booked0 / 2726 / 27
Showings moved0 / 31 / 3
Showings cancelled0 / 22 / 2
Showing outcome (no-show, recorded)0 / 30 / 3
Notes19 / 2119 / 21
Calls logged11 / 1111 / 11
Application sent12 / 1912 / 19
Card made by hand17 / 2317 / 23
Staff texts88 / 11488 / 114
Staff emails to the shared inbox5 / 55 / 5

Built on the Nov 2 POC's contract (Situs Onboarding lane): neutral contract under src/lib/domain/pms/office-activity/, AppFolio adapter in the integrations layer, harness and 58 scrubbed fixtures under scripts/coworker-harness/office-activity/, branch fede/office-activity-harness pushed as a backup only, no PR, no CI. Robot: 59 card reads + 58 showings reads, read-only, no login. Atlas row added. Not done: drift test and hash lock, README, the Sep 1 dump replay.

3. Corrections from the independent pass

Bottom line. "A refactor first" is mostly false; what is true is narrower: give the existing door the office record as an input and have the five callers ask it.

#ClaimWhat the code saysWhere
1The one function "never says stay silent"It does: the turn-start ask returns silent when a teammate holds the thread, and the before-draft door has seven silent rules; only the supervision ask never does.should-speak.ts, should-speak-before-draft.ts
2"Already the only door for every reply and send"Overclaim: the build check only catches copies of the review-hold rule, and five other "is a person on this" deciders live outside it.check-should-speak-duplicates.ts, wake-on-reply.ts, decide-follow-up.ts, first-touch-decision-log.ts, guest-card-reply-eligibility.ts
3The wake "reads texts only"False: it reads the whole thread, so an office call filed on Norma's thread before 17:20 would have kept Clara quiet; Norma is a late call record as much as a missing showing read.wake-on-reply.ts, pbx-call-record.ts, ingest-pbx-recording.ts
4Old step 4: "fill shouldSpeak with the model read"That file must not load the model client (the text and email bundles import it), so the model read lives in the before-draft door and is handed to the wake and cadence callers.should-speak.ts, should-speak-before-draft.ts
5Old step 3: "silent tour row: no workflow start, no message"A confirmed tour row is not silent today: the walker starts reminders and sends the application link, the team gets a confirmation email, and the showing write-back fires.tour-cohort-walker.ts, send-pm-tour-confirmation.ts, showing-sync-stream-consumer.ts
6Section 6: follow-through calls the one functionNot today: follow-through has its own mode (default off) and its own read, sends nothing yet, and would become a sixth door.follow-through/mode.ts, activities/follow-through.ts
6b"Four gates start a turn without asking it"Partly wrong: the wake's turn goes through the before-draft door (which said "reply" for Norma because nothing was on the thread), follow-ups ask it at send time, tour timers skip the teammate stop on purpose and voice answers every caller by design; the gap is the missing office input, not a missing ask.pms-mirror-reply-wake.ts, conversation-manager.ts, tour.ts
7"Intake parks a card assigned to a person" (Fable memo)False: the assignee check has no caller, so "built, never wired" is right.guest-card-reply-eligibility.ts, guest-card-reply-intake.ts
8Follow-up check counts staff texts only (Fable memo)False: it counts any staff message on any channel.staff-touched-since.ts
9Availability reads our tours onlyIt also reads connected host calendars, where AppFolio copies Situs showings (#24585), so those already show as unnamed busy blocks.busy-source-union.ts, check-availability.ts
10Oct 21 "always yes" contradicts a default-off importNo: Oct 21 removed the switch on Clara writing showings into AppFolio; importing with no switch rests on the Sep 30 rollout rule (a read that sends nothing).#21699
11Table 1, staff email: "follow-up check only"It also stops the wake when it is the newest office row.wake-on-reply.ts
12Table 1, logged call: "once per card, dark"Notes and calls also arrive live in the card's newest notes, by day, with no author (11 of 11 calls in the harness).guest-card-mirror.ts, harness assemble.ts
13Missed by all three reviewsA neutral seam for outside tour changes already exists and names "showing on the PMS card" as its next source; the staff-showing import should be its second source, with the harness's showing shape merged into it.external-change/types.ts, reconcile.ts
14Missed by all three reviewsText-pattern deciders are still live on this path ("I'll call you", "stop texting me", the bare-closer words), each against Fede's Nov 2 reasoning rule.decide-first-touch.ts, decide-follow-up.ts, should-speak-before-draft.ts
15"Teammate replied" holdConfirmed: set only by a live teammate text at companies texting through AppFolio, never released; the comment saying the mailbox also sets it is out of date.file-message.ts, conversation.ts, should-speak.ts

Confirmed as stated: the Oct 14 one-decision gate was never on main; first touch is log-only; the notes import runs once per new card behind a default-off setting; the notes classifier has no caller; nothing imports staff-made showings. Harness re-run offline: same numbers (152 → 181 of 228; dropping the showings source returns 152; zero network calls). Limits: every note, call and showing it found carries no named person; truth labels are model-made, 4 cards checked by hand; the adapter's hard-coded Mountain time and notice-wording match are fine for a prototype, a defect in the product. Source: code origin/main a3cdc6bbeb, harness fede/office-activity-harness 4091695854.

4. Path forward, rebuilt: see first, decide second

#What shipsWhat customers noticeProofSwitchNeedsFede?
1Office record, read only. One read per card through the adapter (showings, notes, calls, assignee, status) when a renter's text wakes Clara, when a follow-up is due, and on a calendar tick per company. The notes import loses its setting and its once-per-card limit. Measure how late office calls are filed, then write the call's heading row when the recording lands, before transcriptionNothingLive, read-only at Situs against the day's AppFolio calendar; rate-limit errors flatNone (sends nothing)—No
2One ownership read in the existing door, adding quiet only. The model reads the thread, roles and office record: "does a person at the office own this now?" The turn-start check, the wake, the follow-up check and first touch ask it. It can only make Clara quiet where she speaks today; every existing stop stays until C1 is answered; if the record can't be read, today's answer standsClara stops talking over staff (the Norma and Matthew shape)Replay of real Situs and Western Slope threads with a control, then one real end-to-end run: staff book in AppFolio, the renter texts, Clara stays quiet, record ids keptNone (a fix)1No (Nov 2/3 rulings)
3A staff showing becomes a tour in a "human-booked" state, through the existing outside-change seam: booked, moved, cancelled, host changed. The reconciler, confirmation email, write-back and availability all respect the stateNo times offered against a staff showingReplay of the 507 Situs showings: zero sends, zero AppFolio writes; control: remove the state and the reconciler goes red. Then one live caseNone (sends nothing)1No (decided Nov 4)
4Tour steps read the thread and the current host (rules R and H)No "how did the tour go?" after a cancel; the right host gets the noteReplay of the 79 moves, then liveNone2, 3No
5New capabilities: Clara speaks on human-booked tours (reminders, codes), and picks a thread back up when the renter is waiting on nobody. Retires the never-released hold and the wake's listClara helps on staff-booked leadsSandbox company in Situs's shape, end to endPick-up uses follow-through's existing mode; tour messages get one company setting, default off2, 3C1, C2, then turn-on

Step 3 is decided. Fede took the human-booked tour row (silent, no switch) on Nov 4 evening; it is being built now. A confirmed tour row is not silent today: the tour walker starts reminders for a future tour and sends the application link at once for a recent past one; the team confirmation email fires when a tour turns confirmed; the showing write-back fires on every tour row. Each of those must refuse the human-booked state, each proven with a planted-defect control.

Steps 1 and 3 run side by side. Live runs in steps 2 to 4 need a real AppFolio test card; reopening Willows is Gera's call (ask Smith on the bridge). Stop: wake-list patches, timers, a second decider, confirm-or-cancel and group texts until step 3. Follow-through must ask the step-2 read before it sends. Where: tour-cohort-walker.ts, send-pm-tour-confirmation.ts, showing-sync-stream-consumer.ts, external-change/reconcile.ts.

5. Decisions for Fede (three; (a) recommended on each)

  1. C1. Once the office has spoken on a thread, may Clara ever speak there again on her own? Fede ruled yield + next-day re-check, Nov 4 (session 006; quotes relayed): "we need to be smarter here", "a human touched it during the day great, but then we need to check next day and see if we need to follow up", "not stay silent forever", "if a reschedule didn't happen why not have Clara follow up the next day… try a few times to reschedule". Joint wording (this lane + 006): (1) the read answers "does a person at the office own this thread right now": yes while the newest office-side row is a staff message or note, a human-booked tour is upcoming or ended less than N hours ago, an office call is filed on the thread in the window, or a named assignee touched the card today; the never-released hold becomes this derived answer, no flag. (2) When a person owns it, Clara yields, never mutes: the yield opens a Clara-held follow-through item due the next business morning (sooner only if the ask is time-bound). At due the same read runs again: still owned, stay quiet and read again next morning; no longer owned and the renter is waiting, or a promised step (reschedule, link, answer) never happened, Clara follows up with her normal cadence (one reschedule try). The clock only wakes the read; the read decides. No thread is left without an open item after a yield. (3) No pushes while the office owns it. Known gap: office calls land on the thread 40 to 70 min after the call, so the read can be early by that much. Split: 006 owns the read and every caller of it; this lane feeds it human-booked tour rows and office-activity entries (with a filed-at time on calls) through the person picture only.
  2. C2. Should Clara ever message renters about tours staff booked? (a) build it dark, then turn it on per customer once their own AppFolio reminders are off. (b) never; she only stays out of the way. Recommend (a). Parked (Fede, Nov 4: no notifications for now; "what?" on the question): nothing changes tonight; re-asked after the silent tour row is live.
  3. C3. What Clara may use from staff notes (can wait until after step 3). (a) the facts that change what she says (time, host, code sent, link sent), never the note's wording. (b) only to decide whether to speak. (c) raw notes. Recommend (a).

The former five, and why only these three remain:

  • #1 Staff-booked showing → tour row. Decided (a), Fede, Nov 4 evening: "we just need a concept of a human manual tour vs Clara booked tour somewhere"; "would we send notifications if we detect a manual staff tour? I don't think we should"; "let's start there". A showing a person books, moves or cancels becomes a tour row marked human-booked; it sends nothing (no text, no host note, no reminder, no calendar event); Clara stops offering times over it and stays out of the thread; her follow-ups pause while it is upcoming, and after it passes today's rules apply. No switch, because a read that sends nothing is a fix under the Sep 30 rollout rule; proving it sends nothing is our job. Building now as one PR.
  • #2 Model read vs a list patch: decided by the Nov 2 "every message … reasoning" rule and the Nov 3 "systematic refactor" ruling.
  • #3 No clock for picking up: decided Oct 16 and Oct 25 (both quoted in the code). Only "may she pick up at all" remains, and that is C1.
  • #4 Walk-ins: not a decision. Decision record 0072 covers what Clara books for someone at the door, not importing a showing staff booked; noted here since decision records are retired.
  • #5 What she reads from notes: real but deferrable; it is now C3.

6. How this relates to "Clara remembers unfinished business" (002)

Same record; not yet the same read. The follow-through brief keeps an open-item list per renter and asks one question at each due time: speak, acknowledge, or stay silent, while tracking the item. Today's replay showed that question is blind to office activity, which is why it talked over staff 7 times in 42. Office activity is the missing input to both: a staff showing or call opens or closes items the same way a staff text does. Follow-through does not call the one function today: it has its own company mode (default off) and its own read, and sends nothing yet. When it starts sending, it must ask the step-2 read first. Supervised follow-through at Western Slope and Situs does not wait on this; nothing sends unseen there.

Not verified by the independent pass: production settings (notes import on only at Sandbox; Situs's text setup); Norma's timing (the 40-minute call-filing lag, and whether her 17:20 prompt held the "showing scheduled" notice; the scrubbed fixture was used, not production rows); session 006's replay numbers (34 of 42; 32 of 36); the Situs data numbers (507, 36 of 47, 43 of 73, 15 of 111, 61 of 202); whether Willows is closed, the AppFolio request budget, and which Situs hosts have connected calendars. Fede's quotes were not re-read in raw transcripts, so every dated ruling is as cited by the page and the code comments.

Read first: where the two designs agree, and where they don't

They agree on the shape. One tour record whoever made it, with an origin, a host and a provider-prefixed showing id. One Temporal run per tour that can start with the state the tour already has; every step first asks "already past, or already done by someone else?" Showings booked in AppFolio become Clara tours and get her calendar event, reminders and after-tour steps. When a person answered the renter first, Clara stays quiet. The north star is all seven AppFolio automatic messages off, each switched off the day its Clara replacement is proven.

They agree on the data. At Situs a person booked every showing this year (Fable counts 390 since January in one source, Opus 495 in another; both say 100%). About six in ten were booked the minute the card was typed in. One booked showing in four was changed afterwards. Renters self-booking on a listing site this year: zero. Staff answered a prospect's text first in 36 of 47 threads.

Where they differFableOpusRecommendation
When Clara picks up a thread a person answered firstStays quiet until the renter is "waiting on nobody" (no open promise from a person).Waits 15 business minutes (5 after hours) with nothing promised, then picks up; company setting, default off.Opus's timer: it is measurable and matches how the VA worked. Ship it as a setting, Situs on after a Willows run.
Asking the renter to confirmReminders ask for a "yes"; silence 30 minutes out tells the host once; no cancel (Fede's ruling today).Clara asks only where AppFolio does not; otherwise she reads AppFolio's CONFIRM/DENY reply.Fede's ruling as the behaviour; Opus's "don't double-ask while AppFolio still asks" as the guard until Situs switches AppFolio's confirm text off.
What sits behind a settingImport itself ships as a fix; only the renter-facing messages on imported tours sit behind one company setting.The whole import (staff, VA and listing-site bookings) behind one company setting, default off.Opus: the import writes calendar events and texts people, so it is a new capability, default off, Situs on after Willows.
AppFolio's after-tour email on Clara's own toursReads it as a company-wide setting the robot cannot untick; proven double.Adds the evidence: at Western Slope AppFolio sent "Thanks for visiting" under Clara's name for a showing we wrote (Oct 18). Situs card 9022 was read before the email was due.Both right. The Willows proof run must check that email, not only the texts before the tour. Keep the second AppFolio ask in today's Situs email.
PR cut7 PRs plus the staff-move chain, ordered by the AppFolio message each retires.7 PRs in 3 groups: fixes with no switch, the import behind a setting, the replacements.Opus's grouping with Fable's "which AppFolio message this retires" column on every PR.

Decisions for Fede (Nov 2 list, superseded by the decisions in the Nov 4 one-pager)

TL;DR: 19 lines, one list for the whole initiative. Yes to all except 15 and 16 (hold).

  1. The tour run starts from any state and every step checks "already past or already done" first: ships as fixes, no switch. Recommend yes.
  2. Showings booked in AppFolio (by staff or the VA) become Clara tours within 15 minutes, behind one company setting, default off; Situs on after the Willows run. Recommend yes.
  3. On an imported tour Clara confirms only if AppFolio did not, puts it on the host's calendar unless an event already sits there, and tells the host once only when someone else booked it for them. Recommend yes.
  4. Clara picks up a staff-started thread after 15 business minutes (5 after hours) of the renter waiting, as a setting, default off. Recommend yes. (Hold means Fable's "waiting on nobody" rule instead.)
  5. Clara's after-tour follow-up replaces AppFolio's "Thanks for visiting" email, and renter replies to AppFolio's own thread are matched to the renter's conversation. Recommend yes.
  6. Listing-site bookings (TurboTenant, Tenant Turner) use the same import path, built last, since none happened this year. Recommend yes.
  7. Situs switches AppFolio's messages off in the order the tables below give, one note per switch, each after its proof. Recommend yes.
  8. Staff-booked showings: Turn-on day: Situs switches off AppFolio's renter showing messages (scheduled, updated, cancelled, reminder, after-showing email); the confirm request goes off when Clara's confirm ask (decision 11) is on. Recommend yes, or renters hear everything twice.
  9. Staff-booked showings: Renters already on the calendar get Clara's intro on turn-on day (6 open on the dump date). Recommend yes, never between 9 PM and 8 AM.
  10. Staff-booked showings: Ask Gera for one real-AppFolio run at the Willows (closed today). Recommend yes; Fairhaven proves only Clara's side.
  11. Confirm or cancel: Build it as a company setting, default off; turn on at Situs after a Willows run. Recommend yes.
  12. Confirm or cancel: Renter wording: "Please reply to confirm you're still coming, or we may need to cancel." (softer: "…so Tessa knows to expect you"). Recommend yes: Fede's wording; fair because nothing is cancelled. The sample below now carries this ask in the Situs team's own words (what the team's own texts show).
  13. Confirm or cancel: No reply by 30 min: one email to the host; the tour stays booked; nothing written to AppFolio. Recommend yes: Fede's Nov 2 ruling.
  14. Confirm or cancel: The fold: with the setting on, a confirmation sends the host nothing. Recommend yes.
  15. Confirm or cancel: Also drop today's "confirmed" text where the setting is off. Recommend hold: Western Slope hosts on texts get it today.
  16. Confirm or cancel: Auto-cancel at the deadline, AppFolio's way. Recommend hold until a month of data.
  17. Confirm or cancel: Setting name tour.requireConfirmation, label "Require confirmation before a tour". It names the policy, not the message: a tour is only kept if the prospect confirms the day of; Clara asks, reads the reply, and acts (keep, move, or release the slot per the no-reply rule); the text is just how the policy is carried out. Recommend yes.
  18. Confirm or cancel: Only Clara asks: before turn-on, check (and if needed untick) AppFolio's confirmation box on the showings Clara books, or renters get two asks and AppFolio cancels. Recommend yes, before turn-on.
  19. Confirm or cancel: Heads-up at 30 min, as built. 45 min gives a driving host more notice but flags more tours. Recommend yes; revisit with data.

Already decided today: no automatic cancel or release of an unconfirmed tour at launch; the host hears once, 30 minutes before, and the tour stays booked. A staff reply addressed to another staff member on a thread Clara is only copied on gets nothing from Clara (fix in flight).

Nov 4: Norma at Barcelona, and what the past rulings say

Added Nov 4, 2026 · Proposed, pending Fede's review · read-only, nothing built, no PR · gleaned from 2,392 docs pages, the repo, and every session folder (Fede's own words only; relayed quotes marked)

What happened. A walk-in at Barcelona (8121 W. 9th Ave, Situs). Deiby made her a 10:00 AM showing in AppFolio. At 10:19 she texted her email address, answering Deiby. At 10:20 Clara woke, asked whether she had made it to the 10:00 showing, and offered times between 11:30 and 4:45. At 10:23 to 10:33 Deiby sent the application link, the lockbox code for a self-guided visit that afternoon (in Spanish), and moved the showing to 6:30 PM. Nothing on main changed since Nov 1 (five live sessions polled). Thread cbbe25a6…; the card says Norma, Deiby writes to "Nataly".

10:00Deiby books the showingin AppFoliono tour row: import not built 10:19renter texts her email(answering Deiby)notice ≠ "office spoke": Clara wakes 10:20Clara: "did you make it?"offers 11:30 to 4:45availability reads our tours only 10:23 to 10:33Deiby: apply link, lockboxcode, moved to 6:30 PMmove invisible to PropFlow Three live rules, none changed since Oct 20, each did exactly what it says. Together they put Clara in the middle of a staff member's own conversation.
The same shape as Matthew (Nov 2): a staff-booked showing, no tour row, Clara speaking as if the card were hers. Deyci (Oct 30) had the first two but Clara stayed quiet because the thread was already on hold.

The rulings that already exist (newest first)

DateFede's words or rulingWhereBearing on this design
Nov 3Self-guided arrival texts wait until 8 AM property time; only emergencies go any hoursession 010 (relayed)Codes on imported tours keep the same clock
Nov 2"we should always check roles"; every inbound message is reasoned by the model, never string-matchedfollow-through brief, global ruleThe wake gate must be a read of the card, not a list of sender kinds
Nov 2Rules R (read the renter's messages before any tour step) and H (the host is AppFolio's assignee) are "a new design", not decidedaboveStill open; Norma needs both
Oct 21"why is there a switch for this? If they have AppFolio it should always be yes" (the Showings switch, deleted)PMS conversationsSaid about our tour → AppFolio. Decision 2 above puts the reverse direction behind a default-off setting; his words cut the other way
Oct 20"Just because we don't have a phone number doesn't mean we fail": the lockbox code goes out 1 h before on every channelself-guided reachOnly runs for tours PropFlow holds; Norma's never existed
Oct 20 (#21315)Clara wakes on a prospect reply unless a teammate spoke after her; AppFolio's automatic texts are notices, never a teammate (Oct 14, #19618)messaging handoffThe live rule. Docs disagreed on whether template texts silence her; Norma shows they do not
Oct 16Clara claims the guest card only after her own message went out; "watch mode no, do not build new things"lead-source gateA staff-made card with a staff-made showing is not hers to claim
Oct 15"yes. if a human starts it we dont intervene"renewals loopGiven on renewals. Applying it to showings is an extension, not a decided rule
Oct 14No fixed waiting time; one decision reads every signal on the card, showings included, before every send. "Either advance them to the stage or don't engage at all"lead-source gate, Opus §6In code today the decision is logged, not acted on. A staff-made tour starts at "booked"
Oct 5A self-guided tour still books an appointmentsession (relayed)Deiby's lockbox visit is a tour, not a walk-in note
Sep 27Clara never stores a lockbox code as a property or knowledge factsession 010 (relayed)Codes are read from the card at send time
Sep 23Hand-booked showings put off "until a second hand booking"; Sep 22 on Clara backing off once Kat steps in: "something we haven't built yet"Fable §6The second booking came Oct 16; still not built
Jun 30Decision record 0072: a walk-in is a lead source with no tour row, not a self-guided tourrepo docs/adr/0072Conflicts with importing a walk-in's showing as a tour; one must win

What Norma changes in the decisions above

The design on this page already covers the import, the pick-up timer and the read-back. Norma sharpens five lines. Each is a yes / hold.

  1. N1. The import's switch. (a) Split by what talks. No switch: the tour row itself, visible to the availability tool and to the wake read, with no workflow start, no calendar write and no message to anyone (a tour Clara cannot see is a correctness gap). Behind the company setting: everything that speaks or writes a calendar on an imported tour (the intro, reminders, host notes, the event). (b) Decision 2 as written: the whole import behind the setting. Recommend (a): it matches the Oct 21 words and the rollout rule (a switch only for a new outbound).
  2. N2. The wake gate. The Oct 14 gate (one decision, every signal on the card) already names "a showing by a human actor" as the strongest sign that a person has the card, but it was designed and never built: no code on main carries it. (a) Build that gate and run it at wake time as well as at intake: the model reads the card (showings and who made them, staff touches, notices, whether the renter is answering a person) and decides speak / stay quiet / tell the host. (b) Extend today's sender-kind list with "a showing notice counts as the office". (c) As today. Recommend (a); (b) is one more hardcoded rule of the kind Fede ruled out on Nov 2.
  3. N3. The pick-up timer (decision 4) runs only on a thread where the renter is waiting on nobody, as read by the same model pass; a staff-made showing with a staff reply inside 15 minutes is never picked up. Recommend yes; this reconciles Fable's and Opus's versions.
  4. N4. Walk-ins. A walk-in whose staff booked a showing becomes a tour (Oct 5: a self-guided tour still books an appointment); decision record 0072 is updated to say so. Recommend yes.
  5. N5. Codes on imported tours. Clara sends the lockbox code 1 h before, from the card, unless the model read shows a person already sent it (Deiby did, in Spanish, at 10:32); never before 8 AM, never stored. Recommend yes.

Replay cases for the harness: Norma (Nov 4, cbbe25a6…, name mismatch and Spanish), Matthew (Nov 2), Deyci (Oct 30), Stephany (Nov 2). Mutation control: restoring today's list-based gate must turn Norma red. Nothing is built until Fede's yes; no PR, no branch.

Staff-booked showings become Clara tours

Today Clara never hears about a showing booked in AppFolio. Situs booked 507 there from January to early September, all by hand (383 by staff, 124 by the VA desk's shared seat). Proposal: every 10 minutes Clara reads the AppFolio showing calendar through the robot (read-only), makes each new showing her tour, introduces herself to the renter and tells the host. The same read catches AppFolio-side cancels and confirmations of Clara's own showings, missed today. POC, 16 real Situs showings plus 3 variants: main gets 3 of 19 right, the branch 19 of 19; 8 of 8 planted bugs caught; 0 sends.

How a hand-booked showing becomes a Clara tour AppFolio calendarevery booking 10 min Adapterneutral record Matchnever copy Clara's Ourscompare with last read Same card + slotlink it, no copy NewClara tour, from staff Tour workflow, started from its statesame timers as the tours Clara books Renterintro · reminders · application link · moves and cancels Host or bookerone note · "confirmed" at T−30 · notes ask at T+30 changed through Clara → written back to AppFolio → next read sees its own change, sends nothing
One read, three outcomes: compare a known showing, link a same-card, same-slot match, make anything else a Clara tour. Then it is the tour machinery Clara already runs.
WhenClara doesRenter getsTeam gets
Staff book a showing in AppFolioReads it within 10 min and makes it her tourA short intro: who she is, the time, the hostThe host, one email, unless they booked it themselves. Nobody assigned: the booker is asked who shows it
Before the tourThe same timers as her own toursReminders the day before and 1 h beforeThe host hears "confirmed they're coming" 30 min before, when the renter said yes
After the tourThe same as her own toursApplication link 1 h after, then the normal follow-upThe host is asked for notes 30 min after
Staff move, reassign or cancel in AppFolioSpots the change on the next readTold by Clara, unless staff already told themThe host, once, unless they made the change
Renter replies to ClaraHandles it as her own tourNormal Clara repliesAppFolio updated through today's write path

Yes / hold: decisions 2, 3 and 8–10.

Full sub-design: where Clara reads showings, the record, matching, exact wording, AppFolio changes, edge cases, PR cut, POC results (click to open)

(a) Where Clara reads showings

Ranked by speed and trust; 1 and 2 together are the design.

#SourceSpeedCarriesVerdict
1AppFolio's showing calendar: the read behind its Calendar page, one call per company, through a new read-only robot routeEvery 10 min, window yesterday to 45 days outShowing id, time, home, host, renter name, phone and card link, status (including "unconfirmed"), notesuse
2The renter's guest card: today's card read, extendedOne card per readAdds email, who booked it and when, who cancelled. The only place that says "cancelled"use to confirm
3AppFolio's reporting API, showings reportUnknownNot verified for our accesscheck later
4The showings report export in AppFolio's screensHourly at bestSimilar, brittlefallback
5AppFolio's "showing scheduled" email to the agentInstantReaches only the assignee; Situs is turning notices offno
6AppFolio's own renter texts copied onto the cardInstantStop the day Situs turns them offno
7Listing sites' booked-showing emails (TurboTenant, Tenant Turner)InstantNone in Situs's mail this yearlater, same contract

The calendar read is a POST, so the robot's write guard must list it as a read. About 100 light reads a day per company.

(b) The record and the contract

Listing-site bookings (TurboTenant, Tenant Turner) use the same record and the same entry point.

FieldExample, as Clara stores it
Showing refappfolio:situsgroup:showing:3934, provider-prefixed, opaque to core code
Start, endSep 2, 4:45 to 5:00 PM Mountain, stored in UTC
HomeProperty and unit refs, plus the label people see
HostThe name the PMS shows; matched to a person by roles in core
RenterCard ref, name, phone, email
StatusScheduled, cancelled or completed; renter confirmed yes or no
Booked byStaff, a scheduler the renter used, or unknown; name and time
Recorded late; cancelled byYes when entered after it happened; staff or renter

Two calls. List a window returns live showings only, so a missing row means "go look". Read one is the only thing that can cancel a tour. Only the AppFolio adapter knows AppFolio; the harness fails if the engine names a PMS.

Start from state: the existing tour workflow starts at "confirmed", with its time and host, so it gets the same timers as a Clara booking.

(c) Matching

QuestionAnswer
Is it ours?The showing ref is already on one of our tours: compare with what we last saw. Never a second tour.
Did Clara book it but lose the id?Same renter card and within 30 minutes of an unlinked Clara tour: link it, no copy. The same 30-minute rule Clara uses before booking.
Known or new renter?The guest card is the record. A known card is the existing person; a new card makes a person from the card's name, phone and email, never from a listing email.
Who is the host?The PMS's name for the host, matched only against people at the company with a hosting role (admin, regional manager, PM, assistant PM, leasing assistant, leasing agent, maintenance). A vendor with the same name never matches; a POC case proves it. No host: the booker is asked.
Which home?The PMS property id, through our PMS link. A home the company has not given Clara is recorded with no messages: the one place a building decides, because the action is about that building.

(d) What Clara does

Exact POC text on real Situs showings (names are role labels):

Renter, text"Hi Renter, this is Clara with Situs Group. Agent 2 set up your tour at Building 9 for Wednesday, September 2 at 4:45 PM with Agent 1. I help the team with scheduling, so if anything changes before then, just text me here."
Booked byThe renter's middle sentence
A coworker"Agent 2 set up your tour at Building 9 for Wednesday, September 2 at 4:45 PM with Agent 1."
The host, same day"Agent 4 set up your tour at Building 32 for today at 11:00 AM and will meet you there."
The VA desk's seat (no person record)"Your tour at Building 41 is set for Wednesday, September 2 at 9:00 AM with Agent 1."

Email-only renters get the same words, ending "just reply to this email".

Host, by email, copy to hello@propflowai.co"Hi Agent 1, Agent 2 booked you a showing: Renter A at Building 9, Wednesday, September 2 at 4:45 PM. Clara is sending their confirmation and reminders. To move or cancel it, change it in AppFolio or reply here."
Booker, nobody assigned"Hi Agent 4, nobody is assigned to host Renter K at Building 32, Tuesday, March 3 at 6:00 PM. Clara is sending their confirmation and reminders. Who is showing it?"
WhenWhatSame as Clara's own tours?
On importIntro by text, or by email when there is no phoneNew wording
T−24 h, T−1 hReminders; any already past is skippedYes
T−30 minHost hears "confirmed they're coming", only when the renter said yes, in AppFolio or to ClaraYes
Confirm-or-cancel setting onWhatever it does for Clara's toursYes
T+30 min, T+1 hHost asked for notes; application link, then the follow-up cadenceYes

Host calendar, no double: if something is already at that time, Clara adds nothing; an empty slot gets the event she adds for her own tours. Staff notes go by email (Situs has no text recipients).

(e) Changes made in AppFolio

In AppFolioClaraRenterHost
Time movedMoves the tour, re-plans reminders"Your tour is confirmed for Tuesday, July 28 at 3:00 PM…", today's staff-move text, unless someone told them in the last 30 minTold once, unless they made the change
Host changedUpdates the hostNothingNew host told; old host gets one line; nobody told about their own change
Renter confirmed (AppFolio's confirm request, live today, also on Clara's bookings)Stamps the yesNothing"Confirmed they're coming" at T−30
Cancelled by staff, or the renter answered DENY to AppFolioCancels only after the card read says so; stops remindersTold, unless they cancelled or were already toldTold once, unless they made the change
Missing from one readOne card read; nothing changes unless it says cancelledNothingNothing

Already told: a staff text or AppFolio notice on the card in the last 30 min that names the new time (or the cancel) keeps Clara quiet. Staff can also email Clara to move or cancel.

(f) When the renter replies

"Can we do 5:30?" or "I can't make it" is handled like any Clara tour, and AppFolio is updated through today's write path. The next read sees her own change and does nothing: no second write, no second message.

(g) Edge cases

CaseWhat Clara does
Already over (recorded after the fact; 24 at Situs this year)Ended under 24 h ago: a past tour, no intro, no reminders; notes ask and application link still run. Older: recorded only.
Starts within the hour (16 of 507)Intro says "today at 11:00 AM"; passed reminders skipped; after-tour steps run
No phoneIntro by email; no email either: the booker gets one note
Supervised modeRenter messages wait for approval like every Supervised message; staff notes still go
Quiet hours, 9 PM to 8 AM (4 of 507 booked then)Text held to 8 AM; if the tour starts before then and there is an email, it goes by email

(h) PRs, order and proof

#PRSwitchSize
1Robot: read-only showing-calendar route; the card read adds status, confirmed and cancelled-by. Sandbox PMS serves the same list for FairhavenNone, read-only~250 lines
2Clara's own showings: AppFolio-side cancel, confirm and move are caught. Neutral record, adapter, the 10-minute read, compare, echo guardNone: a fix, live everywhere~550
3Hand-booked showings become Clara tours: import, host by roles, card as the record, start from state, past, within-the-hour and quiet-hours rulesCompany setting, default off, on the company page; Dark line~500
4Messages for imported tours: renter intro, host and booker notes, the calendar eventRides PR 3's setting~400

This week, targets: Tue PRs 1 and 2 · Wed PR 3 · Thu PR 4 and the Fairhaven run · Fri the read-only replay, then turn-on at Situs on Fede's yes, AppFolio's renter showing messages off the same day.

RungProof
ReplayThe 10-minute read run against Situs's and Western Slope's live calendars, read-only, decisions logged, nothing sent; checked against what staff actually did
FairhavenSitus's centralized shape on the sandbox PMS: book, move, reassign, cancel; test phone and test mailbox; record ids as evidence
Real AppFolioOne hand-booked showing at the Willows, moved then cancelled in AppFolio (needs Gera to reopen it)
Supervised first weekSitus, setting on, AppFolio's renter messages off
AppFolio sends todayClara insteadOff at Situs?
"Your showing has been scheduled / updated / canceled" textsIntro, move and cancel textsYes
"Please confirm your showing" (also on Clara's bookings)The confirm ask (Confirm or cancel)When the confirm ask is on
Showing reminderReminders at T−24 h and T−1 hYes
Automatic after-showing email (278 this year)Application link and follow-upYes
Current-tenant showing noticeNothing yetKeep on; a gap for a later proposal

(i) POC results, Nov 2

3 / 19
right on main today
only the guards main already has
19 / 19
right on the branch
16 real Situs showings, 3 variants
8 / 8
planted bugs caught
0
texts, emails or network calls
send doors stubbed, network tripwired
Case (real Situs showing unless marked)Main todayBranch
Coworker booked it for the host, 2 days outnothing happensintro, host note, 4 timers
Same, company in Supervised mode (variant)nothingintro held, note sent
The VA desk's shared seat booked itnothingintro names no booker
Moved twice, host changed, renter confirmed in AppFolionothingquiet: AppFolio already told
Same, AppFolio's texts switched off (variant)nothingClara tells each move
Host changed onlynothingboth hosts told
Staff cancelled and told the renter themselvesnothingcard read, cancel, quiet
Renter cancelled a Clara-booked showing in AppFolioreminders keep goingcancelled, host told
Renter confirmed a Clara-booked showing in AppFoliohost never hearsyes stamped, T−30 note
Booked about 30 minutes before the startnothing"today at 11:00 AM"
Booked at 9:55 PMnothingintro held to 8 AM
Renter has email onlynothingintro by email
Nobody assignednothingbooker asked
A home Clara doesn't runrightright
Clara's own showing comes back in the readrightright
Clara's write landed but lost the showing idrightright
Recorded after it happenednothingno intro; notes ask, app link
Showing drops out of one readnothingone card read, no cancel
Renter moves the tour with Clara (variant)nothingone write back, no echo
Planted bugCaught by
Clara re-imports her own showing9 cases
No same-card, same-slot link1
A missing row treated as a cancel3
No echo guard15
Quiet hours ignored1
Reminders sent for a showing already under way7
Homes Clara doesn't run not skipped1
Host matched by name only (picks the same-name vendor)9

Not in the POC: the robot route (dump rows stand in), the calendar event, real sends, Clara's free-text replies, and the workflow itself (timers modelled from its constants).

Branch fede/poc-staff-booked-showings (local, never a PR) at 575621f815: npx tsx scripts/coworker-harness/staff-booked-showings/run.ts; red run SBS_ARM=today SBS_STRICT=1 fails 16 of 19.

Sources and caveats

  • Situs robot dump on disk (calendar feed and card activity, Jan 2 to Sep 4, 2026), no AppFolio login: 507 bookings, 79 moves, 66 staff and 53 renter cancels, 259 confirmations.
  • "Assistant Lead" is one of three VA seats, a shared AppFolio login (Situs inbox study), not a bot.
  • Fixtures scrubbed (role labels, last-4 phones, fake card ids) and hash-locked.
  • The POC calls main's real slot rule, echo check, quiet-hours gate and staff-move text (18411eb637).

Confirm or cancel

A new company policy for tours Clara runs, "Require confirmation before a tour": a tour is only kept if the prospect confirms the day of; Clara asks, reads the reply, and acts (keep, move, or release the slot per the no-reply rule; at launch the no-reply rule is keep the tour and tell the host, and releasing is decision 18, on hold). The text is just how the policy is carried out. The reminder an hour before a tour asks the renter to confirm. Any reply counts, text or email. If the renter has sent nothing by 30 minutes out, the host gets one email: not confirmed, still booked, a quick call might help. A confirmation sends the host nothing, so today's "confirmed" note folds in. Nothing is cancelled and nothing is written to AppFolio.

1 HOUR BEFORE Reminder adds the ask 30 MINUTES BEFORE Any reply since the ask? YES, ANY WORDS Host hears nothing SILENT One email to the host A TEXTED YES LATER "Confirmed after all", once NEVER, AT LAUNCH Cancel the tour, write to AppFolio, or message the renter a second time
The tour stays booked in every branch. Any message from the renter after the ask counts, text or email: a yes, "on my way", a question. Only silence is flagged.
Full sub-design: timings, messages, edge cases, PR cut, harness results (click to open)

The plan in one table

WhenThe renterThe hostThe tour
1 hour beforeThe reminder adds the ask (skipped if they already confirmed)NothingBooked
They reply, any words, text or emailClara answers as todayNothing (the fold)Booked
30 min before, silent since the askNothing extraOne email (a text too only if opted in): hasn't confirmed, still bookedStill booked; nothing to AppFolio
A texted yes after thatClara answers as today"Confirmed after all", onceBooked
Setting offTodayTodayToday

What the team's own texts show

Every day-of confirm text in the Situs mirror, Sep 29 to Nov 2 (356 conversations read; full table in the session notes). Most asks are AppFolio's standard text sent under an agent's name; a few the team typed. Showings staff book in AppFolio have no tour row on our side, so attendance comes only from the thread.

What the records showCount
Confirm asks: AppFolio's standard text ("Please confirm your showing: … Must reply with CONFIRM or DENY by …"), Sep 30 to Oct 30 · typed by the team62 · 12
When the standard ask goes: before the tour, median (range) · its deadline2 h 4 min (49 min–2 h 9 min) · 1 h before, 61 of 62
Standard asks answered before the tour · before the deadline44 of 62 · 34
Reply speed, median (41 distinct replies)14 min
Replies: the word CONFIRM · another yes ("Ok", "Yes", "Y", "I will come on time") · cancel or DENY · reschedule or late · other22 · 8 · 5 · 3 · 3
Plain-words yeses that got AppFolio's "Your showing has been confirmed" within seconds8 of 8
Typed asks answered: first asks · nudges after silence1 of 2 · 3 of 10
No reply before the tour (18): staff nudged · cancel notice after the deadline · moved by staff · agent went anyway · renter turned up unconfirmed · nothing further in records (one showing can sit in two groups)6 · 1 · 2 · 1 · 2 · 5
Tour outcome rows for these showingsnot in records

Read it as: the standard ask gets the replies (44 of 62); the typed ones are too few to rank. The team's own words, when they type, carry the same two parts: the word CONFIRM and a "no later than" time. Silence rarely ends in a cancel in these records: one cancel notice in 18 unanswered asks, and one agent who went anyway. AppFolio's help describes an automatic cancel at the deadline; whether it is on at Situs is not in records. Agents also tell renters ahead: "an hour or two before the showing you will receive a text message from us to confirm."

Where AppFolio's ask comes from (read Nov 2, look-only)

AppFolio has no company switch for the CONFIRM/DENY text. It is a box on each showing ("Request confirmation by Prospect: Text"), ticked by default on the blank form, sent as the assigned agent about 2 hours before with a 1-hour deadline. Every showing a person booked Oct 12 to 30 had it on; the only two since (Patricia Oct 31, Stephany Nov 2) were booked by Clara, and our robot creates and moves every showing with that box off (unchanged since Sep 22). That is why the template stopped and the showing host typed the ask by hand. AppFolio does not cancel on silence: past showings still sit at "confirmation pending". The renter's reply lands in our thread through the mirror. The Showings Settings page itself is not readable by the Clara login.

Tour booked byAppFolio asks?What Clara does todayUnder this design
Clara (robot writes the showing)No, box off1-hour reminder, no askClara asks at 1 hour, reads the reply or silence, acts
A person, in AppFolioYes, 2 h before, 1 h deadline, no cancelNothing (no tour on our side)Never a second ask: read AppFolio's ask and the reply or silence, act (needs the staff-booked-showings import and the external-updates step; a DENY is a cancel to reflect)

Open for Fede: (a) keep the robot's box off and let Clara own the ask on her tours (recommended: one voice, one deadline, action on silence); (b) tick the box on Clara's showings and have Clara only read the reply (two senders on one thread, no action on silence).

What others do

WhoWhen they askNo replyAfter a no-showWhen staff text the prospect
EliseAIConfirms at booking. Reminder 23 h before if booked more than 2 days out, 3 h before if booked 1 to 2 days out, none if same-day (vendor claim)A reminder call; never cancels (vendor claim)Text 2 h after a missed tour: "Were you able to chat with our leasing agent? If not, I'd be happy to get you rescheduled…" (vendor claim)Elise keeps running; turning her off is a deliberate step with a reason and an end date (vendor claim)
ShowdigsConfirm about 4.5 h before, reminder about 2 h, final 45 min (vendor claim)Auto-cancel (vendor claim)Not statedNot found
ShowMojo2 h reminder, up to 3 confirm attempts (vendor claim)Auto-cancel if enabled (vendor claim)Agent marks the no-show (vendor claim)Not found
AppFolio standard ask at SitusAbout 2 h before, deadline 1 h beforeNo auto-cancel seen in recordsNot in recordsNot in records
Clara (proposed)Ask 1 h before, deadline 30 min beforeKeep the tour, tell the hostNot part of this decisionToday a "human replied" hold silences her

EliseAI keeps working when a staff member texts the prospect, while Clara's "a human replied" hold silenced her on Stephany's "switch to 3pm" text today (a staff member answered by hand). Sources: support.meetelise.com/hc/en-us/articles/32499730992653, showdigs.com/property-managers/showing-confirmations-reminders-showdigs, showmojo.helpjuice.com/the-details-behind-automated-showing-confirmation.

What the renter and the host see

What the renter sees (the one-hour reminder, from the harness):

Clara → renter, 1 hour beforeHello Rosa! It's Clara from Fixture Commons. Please confirm your scheduled showing by replying CONFIRM to this message no later than 3:00 PM so we can ensure someone is available to meet you and show you around the property. Thank you!

Team's own wording, 12 real typed texts (plus 62 AppFolio standard asks sent under their names), Sep–Nov 2026: "Hello [renter]! Please confirm your scheduled showing by replying CONFIRM to this message no later than 1:25 PM so we can ensure someone is available to meet you and show you around the property. Thank you!" (an assistant property manager, Nov 2).

What we change on purpose: Clara reads any reply as the answer, in any words or language (a yes, a "can we do 3 PM", a cancel), not only the word CONFIRM; AppFolio's text missed a Spanish "Si" and stamped "Can I go at 3:20" as confirmed.

What the host sees if Rosa stays silent:

Clara → host, email, 30 minutes beforeRosa F. — tour not confirmed at Fixture Commons
Rosa hasn't confirmed the 3:30 PM tour; no reply to my reminder an hour out. It's still booked. Might be worth a quick call before you head out.

How often (estimate): Situs renters answered AppFolio's ask within 30 minutes 26 times of 44 answered asks, within 90 minutes 39 times (62 asks, Sep 30 to Oct 30). At that pace, asking at one hour flags about 36 of 62 tours (58%); asking at two hours, about 23 (37%).

Folding in today's "confirmed" note

Today

Rosa confirms: the host gets "Rosa F. confirmed an hour out" by text only (Situs: never arrives). Rosa is silent: the host hears nothing.

Setting on

Rosa confirms: the host hears nothing. Rosa is silent: one email. A late texted yes: "confirmed after all". The host hears only about tours that need her.

With the setting off nothing changes, including today's text (decision 15).

The setting

Company switch tour.requireConfirmation (POC: tourConfirmBeforeDriving), default off, on the company settings page. The screen is Gera's lane; the PR ships the key, resolver and API. Dark line:

Dark: tour.requireConfirmation | feature: renters asked to confirm in the one-hour reminder; the host is emailed once 30 min out if they haven't | proof: pending | turn-on: Fede

Edge cases

CaseWhat happens
Booked inside the hourNo reminder, so no ask and no heads-up
Already confirmed (e.g. the day before)No ask in the reminder; the host hears nothing
Reply after the heads-upA texted yes: "confirmed after all". A reply in other words or by email: the host is not told yet (gap, closed in PR 2)
Virtual and self-guided toursNo ask, no heads-up: nobody drives
Showings staff book in AppFolioNever imported today, so Clara never reminds or asks; AppFolio's own text still applies there
Supervised modeThe reminder waits for approval, so nobody was asked and no heads-up fires. Finding: when a heads-up did fire in Supervised (one planted-defect run), the email was held for review, against Fede's Oct 16 rule that staff notices flow. Check on main.
Quiet hoursThe ask rides the existing reminder, whose send path already applies quiet hours; the heads-up goes 30 minutes before a tour, inside working hours
WeekendsThe weekend check-in replaces the one-hour reminder, so no ask goes. Its own heads-up is text-only, so Situs gets nothing: fixed in PR 3
Renter with no phoneThe emailed reminder carries the same ask; an email reply counts
Host with no phone (all of Situs)Email is the default channel, not a fallback
The check runs twiceStill one email: its identity is the booked time

PR cut and proof

PRWhatKindSize
1The switch (key, resolver, API, row on the company page) and the ask in the one-hour reminder, English and Spanishnew, dark~150
2The 30-minute heads-up (email first), reply-since-ask, the fold, "confirmed after all", any later reply passed to the host; plus row 6's honest "I'm here" wordsnew, dark; the "I'm here" words are a fix, live everywhere~300
3Weekend heads-up by email too; an emailed yes counts as a confirmationfix, no switch~150
laterAuto-cancel at the deadline, only on Fede's yesnew~100

Source lines, estimated from the POC; written against main, which the POC branch is behind.

Proof ladder (each rung with record ids):

  1. Read-only replay of Situs's last 60 days of showings: who would be asked and flagged, next to what staff did.
  2. Willows live run on Fede's go, a test phone and mailbox as the renter: silent, yes, late yes, email-only.
  3. Sandbox company in Situs's shape (email-only hosts): the same four runs.
  4. A supervised week at Situs after turn-on.

Harness results

23 cases through Clara's real reminder, heads-up and "I'm here" code, today and on the branch. 9 come from 6 real Situs cases; the rest are their edges.

GroupToday's codePOC branch
"I'm here" from the curb0 of 33 of 3
Confirm flow (silent, voicemail, late yes, yes in words, "on my way", email-only both ways, run twice)0 of 99 of 9
Controls (setting off, confirmed with it on and off, day-before yes, self-guided, virtual, booked late, Supervised, two "I'm here")9 of 1010 of 10
Known gap: after a heads-up, an "I'm here" reaches the host only, not the office0 of 10 of 1
Total9 of 2322 of 23
0
messages sent, every run
every send door stubbed and counted
0
tours cancelled, AppFolio writes
the cancel plant queued 7: caught
11 / 11
planted defects caught
Planted defectCases that went red
Clara says "they'll be ready for you" again3
"I'm here" words ignore the heads-up1
No "confirmed after all"2
Heads-up though nobody was asked1
The reminder drops the ask11
The fold is lost: a confirmation texts the host1
The deadline cancels the tour (AppFolio's way)6
Only a stamped yes counts as a reply3
A retried check emails the host twice1
Heads-up by text only, like today's weekend one6
The heads-up promises to pass on any reply1

Not proven here: no live run; Clara's own replies and the yes/no reader were not run (each case sets whether a reply was understood as a yes); the workflow's timers are emulated; whether AppFolio ticks its confirmation box on showings Clara books is unverified.

Sources and caveats

  • Situs: AppFolio's texting log, Sep–Oct 2026, read-only. Follow-ups: 35 "confirmed", 6 "canceled", none to the 17 silent renters. 56% and 39% are estimates.
  • The hub's 66 staff / 53 prospect cancels (884 cards) are a separate count, not re-checked.
  • No phone on file for 8 of 8 active Situs staff: another session's read, Nov 2.
  • AppFolio help articles: Schedule Showing notifications; showing settings.
  • Fede, Nov 2, on the deadline: "releasing the slot 30 minutes if nobody answers, I don't know if we should launch like that… Maybe the design is instead we email the person that's doing the tour."
  • POC (local, no PR): branch fede/poc-va-arrival-confirm, code 8d2837a8cc, results 0b94bb599c, red on base 1eb03bef13, harness scripts/coworker-harness/va-ways-of-working/__tests__/arrival-confirm.harness.ts.

When the PMS changes: one mechanism for outside updates

Related design, owned elsewhere: Clara re-engages when a human drops the ball (speak / stand down / re-engage when a teammate takes a thread and goes quiet, plus the team's daily list of items nobody is on; Proposed, nothing built). Split: this page owns the PMS inputs that read needs (current assignee, showing status, staff-booked tours created from the PMS, tour-row corrections); that page owns the rule and its proof; the Clara Refactor lane owns the shared context loader.

Proposed — pending review Nothing is built from this page. First consumer, in progress: a showing a teammate moved, read from their reply and checked against AppFolio; cancels wait for this design.

We write back to the PMS, but also if the PMS changes we should reflect that on our side. Two-way syncs are risky, so this is two one-way flows with one owner per field: Clara's changes go out through the outbox; PMS facts come back through one reconciler.

59 s
AppFolio's notice of Stephany's move reached us
nothing read it
13 min
until a person fixed our tour
Nov 2
0 of 27
staff-booked Situs showings we hold
Oct 19 to Nov 2
18
reads an hour to watch Situs
estimate, ~1% of budget
The return flow WAKE OR SCHEDULE ADAPTER, PER PMS ONE RECONCILER OUR SIDE Signals wake a read AppFolio notices staff texts (model read) Schedule, the floor calendar every 10 min tours due in 48 h: 5 min nightly full read AppFolio card + calendar reads Yardi calendar window read neutral events only: prefixed ids, our words Reconciler last-seen mirror + hash owner per field wins echo check cancel + new = moved one fact key per change runs during holds e.g. showing 4082: 2:00 PM → 3:00 PM Our record origin: external Tour workflow signal per fact Audit trail drift per sweep Outbox → robot write Clara's own changes only never sends origin: external
The return flow. Signals wake a read; the read decides. Only the adapter knows the PMS.

The rules

  1. One owner per field. The PMS owns its facts; Clara owns her messages, notes, reminders and the confirmations she collected. The owner wins; no approval button.
  2. Last-seen mirror. A change is "the read differs from the mirror", never "the newer clock".
  3. Once per fact. One keyed Temporal signal per change, also during a "human replied" hold.

What each change does

Change in the PMSReal caseToday on main (d95131e)What the engine does
Showings
1. Staff move oneStephany, Nov 2: 2:00 to 3:00 PM, at her requestShowings are read only just before Clara's own create or move; nothing updates our tour (domain/pms/guest-card-outbox-drain.ts:3181-3191, 3362-3375). Fixed by handMove the tour, tourRescheduled; reminders follow
2. Staff cancel oneDiego, Maria, Lynette, Oct 21 to 28 (no Clara tour)Nothing; the stuck-slot sweep only alerts (app/api/cron/stuck-tour-slot-sweep/route.ts:2,12)A card read confirms, then tourCancelled; host told once
3. Staff rebookDiego, Oct 28: 4:30 PM cancelled 12 min before; another home next morning, booked 22 min laterNothingA cancel and a new showing on the same card within about 25 min, in either order, are one move (tested)
4. Staff mark shown or no-show; renter answers AppFolio's CONFIRM/DENYPatricia: still "scheduled" after her 11 AM tour, CRM status "completed". Deyci: "prospect confirmed"Our showing statuses are scheduled, canceled, no_show, other (domain/pms/guest-card-writer.ts:514)The adapter maps every raw status to ours; a DENY is the renter cancelling; "completed" set by AppFolio's clock is not a visit
5. Staff book one directlyDeyci, Oct 30 (POC below); 27 in 14 daysNo tour rowCreate the tour: the import in Staff-booked showings, behind its setting
Guest card
6. Staff reply to the renter43 of 73 Situs threads active today were on "human replied" holdMirrored within about a minute (pms/pms-inbox-watch-job.ts); Clara stays quietThe model reads it; if a fact changed, read the card. Runs on hold
7. Staff edit contactJensen C.: three texts to a dead numberCard read every minute, but contact only fills empty fields (domain/pms/writers/guest-card.ts:371-372)The PMS value is added; the channel the renter replies on stays first
8. Staff close as lost—Status copied only onto an untouched new prospect (writers/guest-card.ts:76-77)Stop follow-ups; an open tour follows its showing
9. Staff merge two cards—Our own merges are followed (writers/guest-card.ts:2183); AppFolio's: unverifiedFollow the surviving card
Unit
10. Leased, held or off market; rent, special or available date changes—Read every 5 min (lambda/appfolio-sync/handler.ts:5954)Stop offering it; correct a quote Clara gave in an open thread
Application and lease
11. Application status; lease signed or move-in set; cosigner or roommate added—Read every 5 min (domain/pms/writers/rental-application.ts:269)Same event shape into the existing flows
Every change
Owner of each fieldThe PMS for every fact it holds. Clara for her messages, notes, reminders and the confirmations she collected.
How fast we see itAbout 1 min when a signal fires; 5 min for a tour due within 48 h; 10 min through the calendar read; 24 h at worst.
Clara said something now wrongA new outbound behind a company setting, off by default, never at a Preview or Off building. With it on: one correction per fact, never twice, and none if a person told the renter from 30 min before to 3 min after the change (E2).

How we notice: do we poll?

Yes, targeted, signals first. Cards, units and applications are already read every 1 to 5 minutes; showings are not.

PathAppFolioYardi (Yale 25)DelayReads an hour, Situs (requests)
Signals wake a read (first)AppFolio's notice email and text, and staff texts, reach our thread through the inbox mirror in 26 to 66 s (7 measured). Notices fire only on changes a person makes (our robot writes with them off) and stop if Situs switches renter notices off (decision 8)None known: no webhooks for a browser login, no texting mirror~1 min1 read (3 requests) per change, ~2 a day
Targeted poll (the floor)Calendar read every 10 min (route not built) plus one card read every 5 min per tour due within 48 hCRM IQ calendar through the browser agent, planned every 15 min; later the API's guest-activity call by date window (no "changed since")5 to 10 min (Yardi 15)6 + 12 = 18 (42) today; ~54 (150) with staff showings imported
Nightly sweepCalendar window plus every open card; counts driftThe same window readup to 24 h~20 a night
no Flat pollEvery open card every 5 or 15 minSame, heavier in a browser2.5 / 7.5 min average204 / 68 (612 / 204)

Requests measured on Situs, Nov 2: 1 per showing read and 3 per card read (plain requests); a full card page in a browser takes 15 to 16. The earlier "37 a page" had no source. Method: Red team, Nov 2.

Four decisions for this design (E1 to E4)

  • E1. Staff change a tour's time or status in the PMS: (a) PMS wins; (b) Clara wins; (c) latest wins. Recommend (a). Yes / hold.
  • E2. Staff move or cancel a tour Clara confirmed. Telling the renter is a new outbound message, so it sits behind a company setting that is off by default and never sends at a Preview or Off building. With the setting on: (a) Clara sends one correction, unless a person told the renter between 30 min before and 3 min after the change. She waits about 3 min, then checks again. The model judges whether the renter was told. Who sent the message comes from the sender's identity, never a signature, and an unknown sender or a failed text never counts. (b) Nothing. (c) Staff approve first (a button we won't build). Recommend (a), with the setting off until you turn it on per customer. Yes / hold.
  • E3. Freshness: (a) signals at once, calendar every 10 min, tours due within 48 h every 5 min, nightly sweep; (b) every open card every 5 min; (c) nightly only. Recommend (a). Yes / hold.
  • E4. Both sides changed one field between reads: (a) owner wins, plus one correction if the renter saw the other value; (b) a person resolves it; (c) latest wins. Recommend (a). Yes / hold.

Two new rules, Proposed (found on Stephany, Nov 2)

Proposed — pending review Fede, Nov 2: "a new design". Nothing is built and no PR or branch is open for either. Both go through the battle test and Fede's review with the rest of this section.

R. Clara reads the renter's recent messages before any tour step. Before a reminder, the after-tour "how was it?" ask, the application link or a chase, Clara reads the renter's messages since the tour was booked or last moved (a thread on "human replied" hold included) and decides: go ahead, skip, or tell the host. Today none of these steps reads the thread, so Stephany's 2:32 PM "I'll have to reschedule" went unseen.

OptionWhat it doesCost
(a) Before every tour stepCatches a cancel or a move in her own words, wherever it landsOne model read per step, a few per tour
(b) Only before the after-tour steps (ask, link, chases)Fixes Stephany's case; reminders stay blindFewer reads
(c) As today: trust the tour row and the holdNothing to buildWrong asks, a link and chases for a tour that did not happen

Recommend (a). Yes / hold.

H. The host follows the agent assigned in the PMS. When staff book or edit a showing, the person assigned in AppFolio becomes the tour's host for the calendar, notices and the after-tour ask. Stephany: a different host took the showing at 1:15 PM; our tour still names Deiby.

OptionWhat it doesCost
(a) Assignee is the host, on import and on every later editNotices reach whoever actually shows the homeAssignee mapped to a person by role, else the company rotation
(b) Assignee only when the showing is first importedSimplerMisses same-day handovers like Stephany's
(c) Clara's rotation decides; assignee ignoredNothing to buildWrong person asked, as with Stephany

Recommend (a). Yes / hold.

What we will not do

  • Write both systems at once, or let the latest change win.
  • Treat an AppFolio email as the fact, or skip echoes by time window.
  • Poll every card on a flat timer, or add a "confirm this change?" button.

Where the code goes

  • Adapter: neutral change events (kind, source, provider-prefixed id, actor's roles); core never names a PMS. The first consumer already uses this shape.
  • showing-sync-stream-consumer.ts is not the seam: it only turns our tour changes into PMS writes; it should skip origin-external ones (no check today).
POC, Nov 2: Stephany, Deyci, Matthew, and every showing Situs cancelled (read-only; click to open)

Case 1: Stephany's move

Mountain time. 8:34 AM Clara booked 2:00 PM and wrote showing 4082. Noon: the pre-tour check took AppFolio's own calendar copy of this showing for a conflict and only noted it (fixed separately, #24585). 1:00 PM reminders. 1:08 PM Situs called; voicemail full. 1:11 PM she asked for 3:00; Clara stayed quiet (the thread was on "human replied" hold). 1:14 PM the staff member agreed by text. 1:16 PM AppFolio's "Showing Updated" email and text, in our database at 1:16:59. 1:29 PM a person moved our tour.

At 1:17 PMAppFolio (showing 4082)Our tourProposed
Start3:00 PM (−07:00)2:00 PM3:00 PM, origin external, history "moved in the PMS by staff"
StatusscheduledconfirmedNo change
SignalThe hand fix sent tourRescheduled at 1:29:03 PM (workflow history)tourRescheduled at about 1:17 PM, fact key = showing 4082 + start + mirror revision
RenterAlready told twice, by the host and by AppFolioNothing
Write-backThe hand fix pre-seeded a preview-only reschedule_showing outbox row (1:29:01 PM) so nothing went backNot needed: origin external is skipped, and since a fix merged at 2:08 PM Nov 2 the outbox reads the card first and writes nothing when the showing already matches

Without the hand fix, the timers would have fired on the 2:00 PM clock: host note 1:30, staff check-in 2:30, "slot passed" and the application link at 3:00 PM, the minute she arrived (inferred from her original timers and Patricia's workflow history). At 2:32 PM she asked to move again; the thread was still on hold when read at 2:34 PM.

Found on the way (3:45 PM, Nov 2): the after-tour "how was it?" email was wrong twice. Clara emailed the original host only (no copy to hello@, as intended since the 12:47 PM change that day) "How was the 3:00 PM tour with Stephany M. at Lampliter?" at 3:45 PM, on time (slot end 3:15 + 30 min, re-based by the move). But (1) no tour happened: at 2:32 PM Stephany texted she had to reschedule, and at 2:49 PM staff offered tomorrow; AppFolio's "Showing Occurred" at 3:00 PM is its automatic start-time stamp. (2) the reassigned host, not the original one, held the showing: the 1:15 PM AppFolio edit also changed the assigned user from the original host to the reassigned one, and our tour still names the original host. Cause: the check-in reads only the tour row and the host's own staff thread; it never sees the renter's thread (on "human replied" hold, so Clara missed the 2:32 PM text) or the showing's assigned user. What would catch it: two new rules, R and H above, both Proposed and not built.

Case 2: Deyci, booked by staff directly

Oct 30, Mountain time: 8:51 AM Clara offered 1:30 or 1:45 PM. 12:54 PM a Situs agent called and booked 3:30. AppFolio's two notices reached our thread 26 and 31 s later. She confirmed on AppFolio's text at 1:30 PM and toured (AppFolio's thank-you for visiting, Oct 31). Background: Situs launch log, touring gaps.

AppFolio (showing 4079)Our sideProposed
TourOct 30, 3:30 PM (−06:00), "prospect confirmed", CRM status "completed"No tour row; prospect still at "inquiry"; thread on holdCreate the tour (origin external, booked by staff); prospect to "toured"

Case 3: Matthew, booked by staff four minutes after Clara wrote

Nov 2, Mountain time: 3:13 PM a Zillow tour request; 3:14 PM Clara emailed and 3:17 PM texted, offering 4:15 to 4:45 today or tomorrow afternoon. 3:19 PM a leasing staff member booked 3:30 PM with the showing agent. AppFolio's "scheduled" email and text reached our thread 33 to 38 s later. No confirmation was asked: the box was off and AppFolio sent no CONFIRM/DENY text, so there was no reply to read.

How it was booked: not visible. Neither AppFolio nor we hold a renter reply, call, text or email before the booking; no Situs call or text conversation in our tables in that hour (phone-carrier logs not checked); the office call recordings we hold stop at about 1:13 PM. Likely a call to the office line or a walk-in; unconfirmed.

AppFolio (showing 4084)Our sideProposed
TourNov 2, 3:30 PM (−07:00), booked 3:19 PM by staff; confirmation box off; status "completed" from 3:30 PM, set by AppFolio's clockNo tour row; prospect still at "inquiry"; thread not on hold, Clara's 4:15 offer still openAt about 3:20 PM, create the tour (origin external, booked by staff); no second ask; Clara's open offer replaced, not repeated

Every showing cancelled in AppFolio, Oct 19 to Nov 2

0
Clara tours still open after an AppFolio cancel
both linked tours read live; both match
3
showings staff cancelled
Diego, Maria, Lynette; no tour row on our side
27
showings staff booked
23 threads, 0 recorded; 1 staff move (Stephany); 18 confirmed on AppFolio's text

Situs numbers used (2:34 PM Nov 2): 3 tour rows, 1 due within 48 h; 17 open guest cards with a conversation, 9 active today; 73 threads active today, 43 on "human replied" hold; about 2 staff-booked showings a day. Reads an hour: today 6 calendar + 12 for one hot tour = 18 (1%); with staff showings imported, about 4 hot tours = 54 (4%); a flat poll of all 17 cards = 204 every 5 min (14%) or 68 every 15 min (5%). Robot reads have no documented cap (logins do: 3 an hour), so the budget used is AppFolio's report limit, 1,440 an hour per database.

How it was read. The 2 tours linked to AppFolio (Patricia 4081, Stephany 4082) were read from AppFolio through the robot's warm session: GET only, one card page plus 3 card reads of 1.9 KB. Both "scheduled", times match ours. Situs has 3 tour rows; the third (Michael, Oct 29) was cancelled on our side and has no showing. The 27, 3 and 1 come from AppFolio's own notices stored on 34 of the 496 Situs threads active since Oct 19, counted once per home and time; the notices were sorted by text matching for this count only. In the design a notice only wakes a read.

Guards and records. Every script ran inside a guard that blocks all non-AWS network calls and all database writes (0 blocked). The card page tried 5 writes (mark as read, an AI text draft, a conversation, 2 telemetry); all were aborted. Temporal: describe, query and history only. Tours 64dfd201 (Stephany), ff5ef864 (Patricia); threads e379ef3e (Stephany), 9278d6a6 (Deyci); AppFolio cards 9028, 9022, 9014. Found on the way, not fixed: Clara's Oct 29 email to Deyci opened "Hi Pedro".

Battle test, Nov 2

Proposed — pending review We replayed every real Situs showing change since go-live (Sep 29) through this design, assuming E1 to E4 = (a). Everything was read-only: nothing was sent and no PR was opened. The model's reads are stubbed with what actually happened, so this tests the rules, not the model. Passing scenarios only show the rules hold on recorded data; the real proof is a live run after you decide.

240 / 240
scenarios pass
216 real Situs cases, one each; 24 controls and red-team variants
8 / 8
controls: a planted bug turns them red, removing it turns them green
38 of 38 planted bugs in all
0
records with an unknown author
of 2,272 since go-live
15 / 111
real changes main handles right today
3 wrong, 91 missed; the design gets 111 of 111
Scenarios, by what they checkScenariosReal casesPass
Who did it: AppFolio's automation, a person (and which one), the renter, Clara, or our own write coming back868686
Card edits: contact, status, closes515151
The renter's words and silences: confirms, cancels, no reply333333
Showings: booked by staff, moved, cancelled, reassigned212121
Red team (below)16016
Stephany, Deyci, Matthew, Patricia, and the 8 controls12412
Staff notes saying the visit happened, or did not888
Applications on the card888
Staff asking Clara or a colleague555
Change in AppFolio since go-liveRealDesign rightMain today: rightwrongmissed
Staff booked a showing71710071
Staff moved one1010109
Staff reassigned the host1010019
The renter declined (DENY) or the team cancelled10101000
AppFolio's clock stamp "Showing Occurred"44400
The renter called it off: no tour22020
Toured, or the renter confirmed22002
Card edits in the four cases (contact, application)22not compared
All11111115391

"Main today" means main with the teammate's-text fix merged (Nov 2). That fix sees exactly one kind of change: a move a teammate announced by text, on a confirmed Clara tour, at a live building. The 10 cancels had no Clara tour behind them, so there was nothing to undo.

Why 71 bookings and not 83. Staff booked 83 of the showings on the calendar since go-live (customer table below). 71 count as new bookings. 3 were rebookings that pair with a cancel on the same card into one move: Angelique 4011 to 4012, Maynor 3989 to 4026, Diego 4073 to 4076. The other 9 were booked before Sep 29, so only their later changes are replayed. Nothing is left over.

Three worst surprises

  1. Stephany (showing 4082) got the wrong host and an application link for a tour that never happened. The leasing agent who took over her showing never became the host. Her "I'll have to reschedule" sat unread on a held thread. AppFolio's 3:00 PM "Showing Occurred" is just its clock. So main sent the notes ask to the old host, the link at 5:15 PM, and queued three chase texts. Patricia (showing 4081) is the same: nobody joined, the clock stamp fired, the link went out. The design gets both right.
  2. AppFolio's automatic emails name an agent as the sender. Reminders, invitations, updates and cancels all carry the assigned agent in From. Production files them as that person. That is what paused Clara on Matthew's thread while her offer was still open. Reading who did something from evidence (the activity log, the roster, timing) instead of the From line resolves every record.
  3. Main misses almost everything staff do in AppFolio. It misses all 71 showings booked by hand: no person, no tour, no reminders, and Clara's open offer stays up. It also misses 9 of 10 moves and 9 of 10 host changes.
Who made each change (records since go-live)Records
AppFolio's automation (automatic messages, clock stamps, integrations)798
A leasing agent, resolved to which one (3 agents)543
The renter490
The two shared VA seats (a person, never one name)201
The property manager195
Our own write coming back (an echo)29
Clara16
Unknown (fails the run)0
All records since go-live2,272

Every record resolves from evidence, never from a signature. The evidence is, in order: our own ledger, the sender's user on the roster, the text's direction code, the activity author (texts and card events only), the clock, a few-second causal join to a showing change, and the full wording of AppFolio's automatic messages. A shared VA seat counts as a person, but never as one named person. "Unknown" fails the run, and there are none.

CustomerRead tonight (GET only, warm session)Showings since go-liveReplayed
Situs GroupYes: showing list, 85 showings, 70 cards85: 2 booked by Clara, 83 by staffYes, every case
Western SlopeYes: showing list once41: 32 by Clara, 9 by someone elseNot yet; the 9 are next
JP&CoYes: showing list once41: 39 by Clara on the Willows test property, 2 otherNo (test traffic)

Red team, Nov 2

22 of 22 pass. Each attack is a real case, a variant of one with one thing changed, or a made-up case where no real one exists (rows 12 and 13), plus a planted bug. A row passes only if its scenarios pass and the planted bug turns them red.

#Attack, or rule kept as isResult
1 (a)At a Preview building a staff move still updates our tour. Telling the renter is a new outbound (company setting, off by default) and never sends at Preview or Offpass
2 (b)A cancel and a rebook on the same card within about 25 min are one move, in either order; 26 min apart they are two (Diego, Maynor)pass
3 (c)"Already told" looks from 30 min before to 3 min after the change, then checks again. A failed text or an unknown sender never countspass
4A clock stamp never means toured. A shared seat is a person, never one named personpass
5The renter says yes to Clara, then DENY on AppFolio: her latest word winspass
6Staff book on a second card with the same phone: same person, Clara's offer withdrawn, no second threadpass
7A contact edit in AppFolio adds a contact; the channel the renter replies on stays firstpass
8Our own write coming back late is an echo; our stale write never overwrites the team's changepass
9A sign-in page, partial read or cut-off list never cancels and never changes what we last sawpass
10A slow read that finishes late is dropped; the same change seen twice is decided oncepass
11After pairing, nothing is written on the cancelled showingpass
12Thirty reassignments in a minute wake one read, and every host followspass
13A move or cancel three weeks out is found; a missing showing only triggers a read of that showingpass
KeepOne owner per field: AppFolio owns the timepass
KeepChanges are found by comparing content, never clockspass
KeepA notice only wakes a read; it is never the change itselfpass
KeepOnly a read of that one showing can cancelpass
KeepEach change is decided once, also while a thread is on holdpass
MatthewAppFolio's automatic reminder that names an agent never pauses Clara's threadpass
VoicemailA leasing agent's 3:44 PM voicemail from the office line is a person on a shared line, never Clarapass
Stephany D1The host follows the agent assigned in AppFolio: old calendar event removed, new one created silently, no renter message, notes ask to the new hostpass
Stephany D2Her cancel by text on a held thread means the tour did not happen: no notes ask, nothing written. A clock stamp alone never means touredpass

Three changes from your review, now in the rules: (a) telling the renter is a new outbound behind a company setting, off by default, never at a Preview or Off building (E2 reworded above); (b) a cancel and a rebook on the same card within about 25 minutes are one move, in either order; (c) the "already told" check looks both ways, from 30 minutes before the change to 3 minutes after, then checks again. The model judges whether the renter was told. Who sent it comes from the sender's identity, and an unknown sender never counts. On the real cases, counting AppFolio's automatic notice as "told" changes no decision.

Still to align: the staff-booked showings rule (e) still counts an AppFolio notice as "told" and tells hosts about a reassignment. The battle-tested rules above count only a person, and the calendar moves silently (Stephany D1).

AppFolio behaviour the design never definedWhat the real records showRule now
What a renter's DENY doesNayely, showing 4038: she texted "Deny". One second later AppFolio logged "Showing Canceled by Prospect"; six seconds later it texted her its own cancel noticeThe renter cancelled: no correction. Her latest word wins over an earlier yes to Clara
How soon our own write shows up in AppFolioWithin seconds, often stamped a few seconds before our ledger time. A call line is dated at the call's start, up to 3 days before we wrote itAn echo is matched by content against our ledger, never by a time window
Does a missing showing mean cancelled?A sign-in page or a cut-off list shows no showings at allOnly a read of that one showing can cancel; a bad read changes nothing
Does "Showing Occurred" mean they toured?Stamped at exactly the start time, to the second, with the last editor's name (4 of 4 cases)Clock only. A person's record or words decide whether it happened
Does "Showing Confirmed" mean they replied CONFIRM?AppFolio also logs free-text replies this wayThe model reads the renter's words

Poll cost, in requests. The "37 requests per card page" figure has no source. We measured our own reads on Situs today:

  • one showing: 1 request;
  • one card, read with plain requests: 3;
  • a full card page in a browser: 15 to 16.
Path, SitusReads an hourRequests an hourShare of 1,440
Targeted, today18423%
Targeted, with staff showings imported54150 (not ~2,000)10%
no Flat poll, every card every 5 min20461243%
Monday burst: 30 reassignments in a minute1 (one read per company per minute)1 to 2under 1%

Method: counted from our own read logs on Nov 2 (85 single-showing reads; 70 cards at 3 requests each; 5 full page loads at 15 to 16 requests to the customer's AppFolio, plus 3 writes blocked each time). Requests an hour = calendar reads × 1 + card reads × 3. Reads have no cap, only logins do, and our own code disagrees on that cap: 3 or 5 an hour.

Gaps the replay found Proposed Each one is guarded by a planted bug:

  • Words after the slot count. Sabrina, showing 4061: the agent texted "Are you at...?", and an hour later she said she needed to reschedule. Up to 48 h after the start, her words can show the tour did not happen.
  • A plain "yes" to a teammate is a confirmation. The model reads it (Leslie, showing 4014).
  • A teammate's note can close a visit, up to 48 h later. One note about an outing closes every showing on it (Sheyla's two homes, noted the next day).
  • Each question to the model names its showing. Without that, Sheyla's "Confirm" to her 7:30 PM showing would also have confirmed her 8:00 PM one.
  • Card closes count per home. Three homes closed in the same second are three closes (Diego).
  • A cancel is dated at the message that called it off, not at the renter's last message (Rita, showing 4025).
  • Tour mode can't come from AppFolio's type field. It said in person for video and lockbox tours (Rodney 4057, Ashley 4063). Open: no rule yet.
Yardi (Yale 25): the same engine, and what is AppFolio-only (click to open)

Same event shape, owner table and reconciler; only the adapter differs. Everything below is from our build notes and Yardi's published API spec. We have no Yardi login yet, so none of it is verified.

  • Reading appointments: phase 1 is the browser agent on Voyager 8 and CRM IQ (ConAm's login), reading the CRM IQ calendar and the guest card's activity, planned "before each booking and every 15 min". Phase 2 is the SIPP API, where every call is a POST; the prospect module's guest-activity call takes a property and a date window. We deferred that module on Jun 29.
  • Change feed: none. No webhooks for a browser user and no "changed since" in the prospect API (maintenance has one).
  • Cost: unknown until we log in. A browser page is heavy (one AppFolio card page in a browser makes 15 to 16 requests to the customer's AppFolio; a plain read of the same card takes 3), so Yardi reads a calendar window per property, not card by card.
  • A moved appointment shows as the same appointment at a new time in the window; a missing one gets a guest-card read before anything is cancelled.

AppFolio-only assumptions to keep out of core:

  1. Notices and the texting mirror as signals. Yardi has none known, so it runs on the poll.
  2. Reading card by card. The adapter needs both "read one card" and "read a window".
  3. The tour's AppFolio-named showing link with an integer id. It becomes a neutral, provider-prefixed reference.
  4. Status words like "prospect confirmed". Each adapter maps to ours: scheduled, renter confirmed, cancelled, no-show, shown.
  5. The report budget and AppFolio's calendar copy are AppFolio features. The renewals reconcile (ADR-0091: pure classifier, apply step, owner wins, rotation cursor) is the pattern to copy, not its AppFolio reads.
Research behind the rules, with its own caveats (click to open)

Two-way sync research, Nov 2, 39 sources. Its bottom line: the safe shape is not a symmetric sync but two one-way flows with one owner per field, a stored copy of the last remote state, change detection by content, and a sweep that always converges. Every published sync that works (HubSpot and Salesforce, Showdigs and AppFolio, Nylas, Dropbox) is built this way. It lists 14 failure modes (echo loops, last-write-wins loss, dual writes, duplicates, missed notifications, invisible deletes, a move read as cancel + new, double notification and others) with a fix for each; the rules, diagram and will-not list above follow those fixes, and E1 to E4 are its four questions.

Caveats the research flags. Not fetched (cited from memory or a search summary): Kleppmann's book chapter, Dynamo, RFC 5546, Workato's loop-prevention page, Cronofy, Merge's deleted-data and sync-frequency pages, Unified.to, Finch, and a Microsoft Q&A thread. Community, not vendor docs: that Microsoft Q&A thread and a Nylas forum post. Jepsen's ~91% loss figure comes from a search summary. "Tell the renter once per fact" and polling hot records faster are inferences, not sourced practice. Whether AppFolio offers partner webhooks is unconfirmed. The cadences on this page are our own design call.

Design A: Fable 5.1 (full design, click to open)

1. The answer in five lines

1. Clara joins a renter's journey at any point by reading what already happened and acting only on what is still ahead. She never redoes a step a person or a system already did: no second confirmation, no "I'm Clara" when a person already spoke, no re-sent link.

2. One tour record whoever made it (Clara, staff in the PMS, the renter on a listing site), with an origin, a host and a provider-prefixed showing id. One Temporal run per tour, started with the state it already has; its timers skip what has passed. At Situs a person booked every showing this year, six in ten the minute the card was typed in: the staff-booked door is the product.

3. Moves, cancels, reassignments and renter confirmations made outside Clara reach that run through the signals it already has; the PMS adapter turns PMS activity into neutral events.

4. On a thread, Clara looks before she speaks: a person's reply after the renter's last message means she stays quiet there until the renter is waiting on nobody.

5. North star: all seven AppFolio automatic messages off, Clara owning every renter touch. Four gaps are built now (staff-booked showings, confirm-or-release, listing-site bookings, the post-showing follow-up); Situs switches each AppFolio message off the day its replacement is proven.

The plan

PhaseWhatPRsProof rung before it is onAppFolio message it retires
0. NowAsk Situs to switch off the automatic inquiry reply ("Thank You for Your Interest in <address>…", minutes after every inquiry, from the assigned agent's address). Clara's first reply is live. Lead-nurturing workflows are already drafts there: nothing to switch.noneSupervised week at Situs (running since Oct 20)#1 (#4a already off)
1. Tour has an originOrigin, host, external showing id, import stamps on the tour; the PMS write stamps its showing id back. No behavior change.PR 1Byte-identical replay of every tour row at the three customersnone (foundation)
2. Staff-booked showing becomes Clara's tourPMS showing activity → neutral event → tour row (renter resolved from the card first) + workflow started as "already booked"; host told in one line; PMS cancel, move and reassignment flow back the same way. Also stops Clara's follow-up cadence from texting a renter staff already booked.PR 2 (fix), PR 3 (renter messages, setting)Replay of the 24 showings Situs staff booked since Oct 20 → Willows run with a hand-booked showing → sandbox company#2 (booking text + email, confirm request), #6
3. Confirm-or-releaseReminders ask for a "yes"; silence 30 minutes out tells the host once; no tour is cancelled. (Sub-design: Confirm or cancel.)PR 4, PR 5 (setting, default off)Willows run → Situs on#3 (auto-cancel)
4. Listing-site bookingsTurboTenant / Tenant Turner "showing booked" emails become the same neutral event; Clara's reminders stay quiet while the site's are on. Last by frequency: 0 self-booked showings at Situs this year.PR 6Replay of the 2026 listing-site booking emails → Willows#7 (self-scheduling)
5. Post-showing follow-upOne thank-you + "how did it go?" + apply path after the tour; renter replies to AppFolio's own email thread are matched to the renter's conversation.PR 7Replay of attended tours → Willows#4 (post-showing email, survey)
6. Staff movesAlready designed and prototyped: propose-and-confirm, reassign (page: Staff Tour Moves and Reassignment). Plus one fix found today: a tour moved after its day-before reminder went out gets no reminder for the new time.PR 2b (fix), PR 8–11 (that page)That page's ladder; 2b: replay of October moves → Willows move after the reminder#2 ("your showing has been updated")

Yes / hold for Fede

All seven: yes. Two gate Situs this week: 2 and 7.

#DecisionRecommendation
1A tour imported after it already happened: within 24 h of its end Clara runs the normal after-tour steps (host asked for the outcome, application link once attended is known and nobody sent it); older than 24 h she records it and sends the renter nothing.yes
2Renter-facing messages on imported tours (the "you're set" line and reminders) ship behind one company setting, default off, switched on at Situs the same day AppFolio's showing confirmations go off. The import itself, the calendar event and the host line ship with no switch.yes
3While AppFolio's auto-cancel is still on and it cancels a Clara tour: Clara says nothing to the renter (AppFolio already texted), tells the host once, and re-offers times through the normal follow-up.yes
4Imported listing-site tours: Clara's reminders stay quiet until that site's own reminders are off at the customer (one line per site on the company page).yes
5No intro and no second confirmation when a person already spoke to the renter; Clara continues the same thread, signed as herself, and takes it only when the renter is waiting on nobody for 15 minutes.yes
6AppFolio's own messages on Clara's showings: the one card Clara booked at Situs (Oct 31, tour Nov 2) shows none of them: no booking text, no "Showing Reminder" email, no confirm request by the time Clara's one-hour reminder had gone. The robot's notify-off holds on that evidence; Fede's note of Nov 2 says they fire. Keep the design for both and settle it with the phase-2 Willows run (one showing booked through Clara, bench phone watched). Auto-cancel: never seen at Situs (0 in the 2026 dump; a DENY becomes "Canceled by Prospect", staff cancel the rest by hand); its toggle is unreadable to us.yes: design for both, prove at Willows
7The Clara AI user cannot open AppFolio's Automatic Communication and Showings Settings pages, so every ON/OFF above is read from what AppFolio sent on real cards, not from the toggles. Ask the Situs org admin to grant that user the settings permission (one line), or to read the two pages for us.yes: the permission, read-only use

The seven AppFolio messages and what replaces each

AppFolio messageClara's replacement todayBuild nowProof rungOff at Situs when
1. Automatic reply to a new inquiry: "Thank You for Your Interest in <address>… to schedule a tour, please reply to this email or call … option #1" (minutes after every inquiry, repeats included, from the assigned agent's address; the questionnaire was never seen)Live. First reply by text (AppFolio texting seat, Oct 29) and email (Oct 28); 12 first-touch emails and 18 texts at Situs so farNothingSupervised week (running)Now
2a. At booking, Clara-booked: "Your showing has been scheduled: <address> <day date time> -- <owner LLC>" text + "Showing Reminder" email (same minute as the booking; five notify boxes ticked by default on the form)Live. Clara's booking confirmation by text or email. AppFolio's did not fire on the one Situs card Clara booked (consistent with the robot unticking the boxes)NothingWillows run in phase 2 (one card is not proof)Per-showing boxes, no company switch: already off for Clara's
2b. At booking, staff-booked: the same text + emailMissing. Clara never learns of the showing; the renter hears AppFolio under the agent's namePR 2 + PR 3Replay → Willows → sandboxPR 3 on at Situs; staff untick the two "send showing details" boxes (a habit; the default sits in a settings page we cannot read)
2c. Day-of confirm request: "Please confirm your showing: <address> Today at 2:30pm… Must reply with CONFIRM or DENY by 1:30pm" about 2 h before, deadline 1 h before, under the assigned agent's name (22 of 23 staff bookings since Oct 20); "Your showing has been confirmed / canceled" replies instant. AppFolio sends no other reminderPartial. On Clara's showings: day-before and one-hour reminders, per slot (more than AppFolio does). Neither asks for a "yes": that is confirm-or-releasePR 4 + PR 5 add the "reply yes"; PR 3 brings the reminders to staff-booked toursWillows → Situs onWith 2d and 3
2d. The same request on staff- or site-booked showingsMissingPR 3, PR 6Replay → WillowsPR 3 on; site reminders off
3. Auto-cancel of unconfirmed showingsUnknown and never seen. 0 auto-cancels in Situs's 2026 dump: a DENY becomes "Canceled by Prospect", staff cancel the rest by hand, and unanswered requests still went on to "Showing Occurred". The toggle is on a page the Clara AI user cannot openPR 4 + PR 5 (confirm-or-release: no cancel, host told once). The human version exists today: staff cancelled 28 never-confirmed showings by hand this yearWillows → Situs onSetting on at Situs; a Situs admin confirms the toggle (yes/hold 7)
4a. Lead-nurturing texts and emailsLive. Follow-up cadence to a quiet lead and re-engagement. At Situs the AppFolio side is already off: the three workflows are drafts, no leasing Realm-X flow runsNothingLive at Western SlopeAlready off
4b. Post-showing email, about 23 h after the slot: "Thanks for visiting <address>", unit facts and the listing line, "For more information or to apply, please contact us by responding to this email or calling us at (303) 789-3030", signed by the owner LLC (5 of 6 occurred showings; also sent to a renter whose application was already in)Partial. Application link after the host marks attended; no thank-you; a renter's reply lands in leasing@ under AppFolio's thread, unseen by Clara. This one is a company-wide setting, not a per-showing box, so the robot cannot untick it: Clara-created showing 597 drew it (Oct 19)PR 7Replay → WillowsPR 7 live, then the setting off
4c. Showing surveyUnused at Situs (the tab exists, zero answers ever). Clara asks the host "how did it go?"; the renter is not askedFolded into PR 7's first after-tour touchSamePR 7 live
5. Hand-sent templates: the VA's "Showing Invitation" email + text ("We received your inquiry for <address>… what date and time would work best…"), the agent's "We have received your application!" saved replyLive. Clara's first reply and time offers; the card shows her claim once her message went outNothing in code; a team habitn/aNow
6. Staff alert emails (the Clara AI user's own: showing created / updated / canceled ON, new guest card OFF; other users' settings unreadable to us)Live. Host emailed on booked, moved, cancelled (Nov 1) and asked for notes after the tourPR 2 adds the same host line for imported tours; AppFolio's showing-created email to the Clara AI user is a second, faster signal for the import (the card timeline stays the source)WillowsNow (keep the inbox alert)
7. Renters booking showings themselves from a listingPartial. Clara books every tour she is asked for; a self-booked showing she never sees can become a second bookingPR 2 (PMS self-schedule) + PR 6 (listing sites)Replay → WillowsPR 2 and PR 6 live

2. The lifecycle, with every door Clara can walk in through

E8 · a person takes the thread over: Clara pauses at whatever state she is in, resumes with a look when handed back or when the renter waits on nobody Inquirylead arrives First replysomeone answers Times offeredwaiting on a pick Bookedtime + host set Remindedday before, 1 h Tour timehost meets renter Outcomeattended / no-show Applylink → application E7 staff move · cancel · reassign (by text, email or in the PMS) E3 staff replied first Clara stays quiet, parks her follow-up E1 staff booked it in the PMS most common door E2 renter booked on a listing site site sends its own reminders E6 Clara added late to the thread any state: read it all, answer the open ask E4 tour already happened after-tour steps only, 24 h window E5 application already in nothing to send the state every door lands in or after; Clara's own path runs left to right a door from outside Clara (orange); dashed = any state
Eight doors, one path. Today Clara assumes she opens the door at Inquiry; every orange arrow is a start she must make without firing the steps to its left.
DoorClara doesClara skipsHost hearsNever repeated
E1 Staff booked the showing in the PMS (today the only ways a person can book: the PMS, or texting Clara's desk; PropFlow's pages cannot create a tour)Adopts it as her tour within the sync's minute: tour row with origin staff, host from the PMS assignee (proposed, rule H), calendar event if none; reminders only for moments still ahead; after-tour ask to the host; application link after attended. With the setting on: one "you're set with <host>, <day time> at <home>; text me here with questions" lineFirst reply, time offers, "please confirm" nudges, any reminder whose window passedOne line: "I have <renter>'s <day time> tour; I'll remind them and ask you for notes after"The confirmation staff or AppFolio already sent; an intro
E2 Renter booked on a listing siteSame import from the site's email; claims the lead; one reply in the renter's thread with what happens next (an intro is useful here: nobody has spoken to them)Proposing times (a second booking path); her own reminders while the site's are onThe normal booked notice, naming the siteThe site's confirmation
E3 Staff replied firstReads the thread; stays quiet while a person owns it (cadence parked); speaks only when the renter writes again and nobody answers in 15 minutes, continuing the thread; books if askedIntro, first reply, questions already askedNothing; the person is in the threadA question staff asked; a link a person sent
E4 Tour already happenedWithin 24 h of the end: asks the host how it went, sends the link once attended is known and nobody sent it, starts the after-tour follow-up from the tour's end. Older: records it, sends nothingConfirmation, reminders, host confirmThe after-tour ask onlyAn application link already on the card
E5 Application already inNothing outbound on the tour; the follow-up stops (it already stops on apply)Link, chaseNothingThe "apply" ask
E6 Added late to an email threadReads it all; answers only the open ask to her or the renter's unanswered one; adopts any tour the thread names (slot match); never proposes a second tourIntro, recap, anything answeredOnly if she books or movesAnything already answered
E7 Staff move, cancel or reassign after Clara bookedPer the staff-move page: ask the renter when staff can't make it, plain confirm when the renter asked, reassign silently. From the PMS: the same path with actor pms; one voice to the renter: quiet while AppFolio's "updated" text is on. Host changes sync in neither direction today (a PropFlow host change makes no PMS action; a PMS reassignment is unread)Rebooking from scratch; a second confirmationThat page's H-linesA notice AppFolio already sent
E8 Staff take the thread over, then hand it backTake-over = a person's reply or "I've got this": every cadence parks. Hand-back = "Clara, take it from here", or the renter waiting on nobody for 15 minutes: she resumes with a look at what changedThe step the person didNothingConfirmation, link, answer a person gave

3. Temporal: one workflow, started with the state it already has

Decision: catch-up, not a start-at-state input. The run already observes the tour instead of assuming it: workflow id = tour id, a second start is a no-op under USE_EXISTING, every timer hangs off the scheduled start, the day-before and one-hour reminders skip once their moment has passed, and every send re-reads the row and quietly skips already-sent. So a staff-booked tour starts the way the cohort walker already starts an auto-confirmed one: write the row as confirmed, then signalTourConfirmed(…, {startIfMissing}); the "please confirm" loop returns before its first nudge. What is missing sits in the adapter and the activities: no PMS code calls applyTourIntent or any signal today, so a showing created, moved or cancelled in the PMS changes nothing here. Two constraints: the run needs a personId (resolved from the guest card first), and the row's existing source: clara | manual | external is written only as clara.

DoorHow the run startsWhat each leg does on its ownNew
E1, E2, E7-in-PMS, upcomingRow confirmed with source: manual | external, hostPersonId, external.showingId, the renter's personId from the card; signalWithStart(tourConfirmed)Phase 1 resolves at once; T-24h and T-1h skip if past; host-confirm leg from T-30; link at start+60 after attended; after-tour follow-up from the end; the lead follow-up cadence stops at its next wake (it reads any confirmed tour)Quiet skip external-reminders on both reminder activities when external.remindersBy ≠ clara
E4 already happenedSame startReminders skip; the link leg fires immediately, and the attendance gate already says "send" two hours after the end, so it would send; the walker's 7-day backstop would tooQuiet skip imported-after-end in sendPostTourApplicationLink (the domain function both the leg and the walker call) and in the after-tour chase when importedAt > end + 24 h
E7 move in the PMS (and any move)Adapter → setTourSchedule(actor: 'pms') → tourRescheduled, as a staff move through Clara's desk already doesLegs still waiting move with the new time. Legs that already fired do not: today no schedule version is ever written (bumpVersion: false, the start never passes one), so a tour moved after its day-before reminder went out gets no day-before, one-hour or link for the new timePR 2b (fix, no switch): every move bumps scheduleVersion; the two reminder legs re-arm after a reschedule, behind patched(); stamps compare per version (the reader already does)
E7 cancel in the PMS (staff or auto-cancel)Adapter → cancel chokepoint with reason: 'pms_staff' | 'pms_auto_cancel' → tourCancelledRun exits cancelled; the renter notice is the chokepoint's, not the workflow's: silent when the PMS already textedReason values only
E7 reassign in the PMSAdapter → hostPersonId + calendar node on the row, history host_changed source: pms_syncNo signal needed: the check-in, host-confirm and after-tour legs read the host at fire time (PropFlow's own host change sends and signals nothing either)Nothing
Renter confirmed through the PMS's own text (CONFIRM)Adapter → recordProspectReconfirm, the path a texted "yes" takes: stamps prospectConfirmed, signals prospectReconfirmed (not tourConfirmed: that one means "accepted the proposed time")Host-confirm leg sends its one "they're coming" lineanswered: 'pms' on the existing stamp
Outcome marked in the PMSStaff's "Showing Recorded" (attended / no-show) → the staff desk's stampTourAttendance → sendApplicationOnAttended, if no stamp yet. AppFolio's own "Showing Occurred" (339 of 394 at Situs have no actor) only means the slot passed: it maps to the existing slot-passed mark, never to attendedLink leg sends on attended, stays quiet on no-show; the after-tour chase startsStatus values in the adapter only
E3, E8 a person owns the threadNo change to the runThe after-tour chase already parks on a human-owned thread (14-day budget); the lead follow-up cadence gains the same parkPark in prospect-outreach-workflow (reads the thread owner at fire time)
Idempotency keyValueGuards
Workflow idtour.id, USE_EXISTINGDouble start, walker + import racing
Import keyexternal.showingId = '<provider>:<id>', unique index → tour id; slot match (home, start, renter) as the fallback for rows written before PR 1Two tours for one showing; Clara's own showing coming back as "staff-booked" (the drain stamps the id on write)
Signal event id'<provider>:<showingId>:<activityTs>:<kind>', stable like the walker's (today's intents build event ids from timestamps, so the run's 256-entry memory never spots a repeat)At-least-once delivery, re-synced timelines
Message stampsPer slot (scheduleVersion): the reader honours a version, nothing writes one todayA reminder for a slot that moved (PR 2b writes the version)
Import windowimportedAt vs end + 24 hA link or chase for last month's tour
FileChangeSize
src/lib/temporal/workflows/tour-workflow.tsSkip the cadence read when the confirm is already in; accept the two new quiet skips; PR 2b: the day-before and one-hour legs re-arm after a reschedule instead of returning (all behind patched())~90 lines
src/lib/temporal/workflows/tour-skip-reasons.tsDocument external-reminders and imported-after-end in the quiet list (never in the failure list, or the step re-runs)comment
src/lib/temporal/workflows/tour-timers.tsNo change: both anchors stay start-based0
src/lib/temporal/activities/tour.ts, tour-row-lookup.ts; src/lib/domain/leasing/send-application-link.ts, tour/send-application-on-attended.tsReminders and the weekend check-in (weekend-tour-checkin.ts, replacing its manual skip) read external.remindersBy; the 24-hour window lives in sendPostTourApplicationLink so the leg and the walker share it; the no_property early return in the attended path goes (company-scope tour instead)~120
src/lib/temporal/tour-client.tsstartAdoptedTour() = confirmed start helper (wraps signalTourConfirmed + startIfMissing)~40
src/lib/temporal/workflows/prospect-outreach-workflow.tsPark a touch while a person owns the thread (same rule as the chase)~60
PMS adapter: activity-kind.ts, card read, showing-sync-stream-consumer.tsMap the three phrases that are unknown today ("Showing Scheduled" 514 rows at Situs, "Showing Canceled by Prospect" 53, "Showing Occurred" 394) and split confirmed / modified / canceled instead of one showing kind; the card's showing read gains assignee, end and unit; each card refresh whose showing activity is newer than lastSeenAt emits ShowingObserved (one bounded read per changed card); route to the tour chokepoints~300
src/lib/domain/pms/guest-card-outbox-drain.tsStamp the created showing's id on the tour~40
src/lib/domain/leasing/tour/apply-tour-intent.ts, set-tour-schedule.ts, tour-event-provenance.tsTrigger pms, classed as not Clara's action (today every trigger but ui counts as hers); source: manual | external on create instead of the hardcoded clara; bumpVersion: true on every move and the version passed to the start; silent-renter rule when the PMS already notified; provenance text "Booked by a person in the PMS"~100
agents/clara/lib/email/parse-lead-source.ts, process-inbound-message.tsTurboTenant and Tenant Turner "showing booked / reminder" shapes → ShowingObserved; such a notice leaves the tour-request path (today ParsedLead has no showing time, id or booked flag)~180

4. Data model

FieldShapeRule
source (existing)'clara' | 'manual' | 'external'The origin. clara: Clara booked it, including on a staff instruction through her desk (bookedByStaffPersonId stays). manual: a person booked it in the PMS. external: the renter booked it on a listing site or the PMS self-schedule page. Defined in types.ts since the field was added, written only as clara today. Its one reader, the weekend check-in's manual skip, becomes the remindersBy rule in PR 3 (or imported tours would never get the Friday check-in once their messages are on); the types.ts comment calling manual "made in the UI" is corrected in PR 1. No new origin field
external.provideropaque string, the prefix of showingIdWhere it came from; data, never a branch in core
hostPersonIdstring | undefinedFrom the staff-move contract, reused. Today the host lives only in calendarNode { kind: person | property | org, id }; the import writes both when the PMS assignee maps to a person (else the property's calendar node). An imported tour is in_person with no video room unless Clara is its host
external{ showingId: 'appfolio:123' | 'turbotenant:abc', guestCardId, assigneeRaw, confirmState: 'unknown' | 'confirmed' | 'denied', remindersBy: 'clara' | 'pms' | 'site', lastSeenAt }Replaces today's Tour.af { pms: 'appfolio', showingId }, the one PMS name on the tour (read as a fallback until backfilled). Provider prefix is opaque to core; remindersBy is set from the company page per provider and flips to clara when the customer turns the PMS or site reminders off; confirmState is mirrored into the existing prospectConfirmed stamp
importedAt, importedWhenISO; 'upcoming' | 'past'Drives the 24-hour window in sendPostTourApplicationLink, shared by the workflow leg and the walker's backstop
history[]existing TourEvent (actor?: 'staff' today) + actor: 'pms', source: 'pms_sync'Audit of every outside change
Conversation threadJoin{ joinedAt, humanTurnsBefore, lastHumanReplyAt, ownerPersonId? }On the conversation, not the tour; the speak / act / stay-quiet rule reads it
Neutral shape (src/lib/domain/pms)FieldsDirection
ShowingObservedprovider, externalId, guestCardId, unitRef, startAt, endAt, assigneeRaw, status: scheduled | rescheduled | cancelled | confirmed | occurred | recorded_attended | recorded_no_show, actor: staff | renter | system | us, observedAtAdapter → core, emitted from timeline activity kinds; routed to the tour chokepoints
ShowingWriteResultexternalIdAdapter → core on create, so the tour carries its id from the first minute

A showing on a home with no mapped property still becomes a tour at company scope, host line to the company inbox; the property is narrowed in when the unit maps.

5. Who goes first, and joining a thread late

Fede, Nov 2: no race rule at Situs now ("expected, we just launched"); what follows is behavior, not a switch. The pieces exist but do not see each other: the first touch skips when a teammate replied and waits ten minutes on a hand-made card; the follow-up gate stops on "teammate answered, no renter reply since" and "staff promise pending"; a staff text through the PMS texting door sets a hold, a staff email none; "coworker acted outside" is classed and then ignored; and "tour booked" reads PropFlow tours only. The thread-owner record and the import make one rule of these.

SituationSpeakActStay quiet
New lead, nobody repliedFirst reply; claim the card after it went outBook when asked
A person replied after the renter's last messageRecord the thread owner; park every cadence touchYes: the person owns it
Renter writes again, nobody answers for 15 minutesContinue the thread, no intro, no recapBook, move, answer
Added to an email thread late (CC, forward)Only the open ask to her or the renter's unanswered askAdopt a tour the thread names; do what a teammate tells her, one line backTeammates talking among themselves
A teammate already answered the ask Clara was draftingPull the draftYes
Tour already booked by a personNo second confirmationAdopt it (section 3)Until the next moment she owns (a reminder, the after-tour ask)
Application already inStop the chaseYes, until the renter writes
Live case, Oct 29 (Situs): Clara texted and emailed a new lead; the renter asked her for a 2:15 slot; the agent asked the team, then called the renter and booked 3:30 in the PMSNothing: a person booked itAdopt the 3:30 showing (E1), park the cadence; today Clara neither knows of the showing nor stopsYes, until a moment she owns
Hand-back ("Clara, take it from here")Resume with a look at what changed since her last touchNext step only

6. Western Slope said this already

Emails, card records and session records read as written. Lines marked raw come from the per-speaker #transcripts text of eleven Western Slope meetings (Sep 4 to Oct 28), never the recap; Kat had no mic of her own, so a † line is labelled Jason and may be hers, and Oct 21 and 28 names were removed at the source. The hand-off is their first ask at every meeting since Sep 16.

DateWhoWhat they said or didDoorAnswer in this design
Sep 9Jay, kickoffAlert the leasing agent the moment Clara books a tour; "if it's in Guest Card, it's good to go"E1Shipped Nov 1 (host email); PR 2 sends the same line for tours staff booked
Sep 16Jason, pre-go-live (raw)"She's getting stood up on a lot of showings recently… AppFolio will be sending them a confirm or deny… that's already happening"confirmConfirm-or-release (PR 4–5); AppFolio's request stays on until it is live
Sep 16Jason† (raw)"even after a showing, they'll send them another reminder. It's weird… the auto responses will turn off"E4AppFolio item 4 off the day PR 7 is live; it is a company-wide setting the robot cannot untick
Sep 16Jason (raw)"I'm out today, and this person's covering me, route this to this person's schedule… let's just book it to Jonathan right now"E7Host from the PMS assignee (hostPersonId; proposed, rule H); reassign on the staff-move page
Sep 16–30Jason, meetings and emails"Maybe we can build some protocol when a live agent should intervene?"; the hand-off is "most friction", "doubling the workload"E3, E8Section 5: a person's reply parks Clara; the renter waiting on nobody for 15 minutes brings her back
Sep 21Email ledgerBev double-booked a tour Clara had already bookedE1One tour per showing, keyed on the PMS showing id (PR 1–2)
Sep 22Jason†, working session (raw)"the two that I just answered to before Clara got to it… I clicked schedule showing… but it did not show up on my calendar"E3, E1PR 2: a showing booked in the PMS becomes her tour, calendar event included
Sep 22Jason (raw)"if Kat intervenes at any point, Clara will just be like, okay, Kat's got it" (Fede: "something we haven't built yet"); "once I jump in… she doesn't jump back in"E8Section 5: a person's reply parks her; "take it from here" or a renter waiting on nobody resumes her
Sep 23–24Kat (session record)Could not take Clara's morning slot, booked the afternoon herself in AppFolio; PropFlow had no tour, so Clara's reminders would contradict her. Fix deferred "until a second hand booking"E1The second one came (Oct 16). PR 2 adopts the hand booking within the sync's minute
Sep 24Bev; Kat, emails"leads are starting to pile up, so I'm not sure whether I should step in"; "If someone calls me directly am I able to schedule my own showing"E3, E1Yes to both: Clara takes new leads, keeps quiet where a person answered; a showing Kat books becomes Clara's to remind and follow up
Sep 25Jason, email"find better ways where Clara is booking a showing even if Kat books it directly"E1PR 2, exactly this
Sep 28, Oct 17Kat, email; card 3012"I accidentally sent an application… Does Clara send one as well?"; Clara sent the link, Kat sent it again 43 minutes laterE4, E8Never repeated: the link checks the card's "application sent" activity first (PR 7); a person's send counts as sent
Sep 29Kat, email"How long should Bev or myself wait to respond if Clara hasn't?"E3Section 5's 15-minute rule, written down for them
Sep 30–Oct 19Shared-inbox studyStaff restarted 6 of 80 of Clara's leads from scratch; "Also ignore Clara" to a residentE8Thread owner recorded; Clara's claim visible on the card; parked cadence never restarts a lead a person is working
Oct 13Sean, our draft to them (raw)"showings Kat and Bev book directly in AppFolio or Rently don't come back to us"E1, E2PR 2 (PMS); PR 6 adds Rently's notice shape if it reaches the inbox
Oct 14Kat, weekly sync (raw)"I already scheduled it verbally with the person"; wants it "entered as a showing that Clara has booked, but doesn't want to trigger Clara going all the way from the beginning"E1The brief, in the customer's words: PR 2 starts the run as booked, nothing to its left fires
Oct 14Jay (raw)"not to send her… hey, it's Clara, I'd like to reach out and schedule a showing… 20 minutes after Kat just recorded that she had a phone call with her"E3A logged call on the card is "coworker acted outside": the first touch skips, the cadence parks
Oct 14Kat (raw)"she said, okay, I'll put it in your notes. And then, a half hour later, she texted me and asked if I had any notes for N."E4The after-tour notes ask checks the notes already given on that thread first (PR 7)
Oct 14Jay, weekly meeting"Don't reach out to him like he's a brand new lead"; "how do I let Clara know not to reach out"E3, E8Look before speaking; "Clara, I've got this" parks her, "take it from here" resumes her
Oct 15–21Fede; working session"Clara can't see communications that happen through AppFolio from you or Bev"; "if it doesn't make it into AppFolio, Clara has no way of knowing"E1, E7PR 2 reads the card's showing activity (scheduled, modified, canceled, confirmed, occurred); the adapter turns it into events Clara acts on
Oct 15–18Card 3012The AppFolio write failed, Kat booked herself, a re-send added a second showing, two "Thanks for visiting" emailsE1Showing id stamped at write; import keyed on it; AppFolio item 4 off once PR 7 is live
Oct 16Kat, email"another no show and if I could've called them I could have found out if they were still planning on coming"confirmConfirm-or-release (PR 4–5): the reminder asks for a yes; silence 30 minutes out reaches the host
Oct 20Kat, email"couldn't confirm the reschedule time because it was in 60 min same day notice window" (fixed Oct 20)E7Staff-move page; same-day moves are the common case there (3 of 7 under two hours)
Oct 21customer contact, scoping call (raw)"hey, Clara, I already scheduled this showing, can you just put it on the calendar with this person? And Clara reached out to schedule the showing"E1, E6Adopt the tour the thread names; never propose a second one
Oct 21customer contact (raw)"I see that Clara is reaching out, but I'm gonna go ahead and call them… then Clara is like, hey, I haven't heard from you, should I turn off your guest card?"; "we've asked our staff to put their hands down"E3, E8The cadence parks on a staff call or note; stepping in becomes safe, so hands need not stay down
Oct 21Working session"be very deliberate on the handoff"; they want "where we step in, where we don't, and what we need to do when we step in to let Clara know"; Clara chased a showing their lead had already setE8, E1Section 5 is that protocol; E1 stops the chase of a tour a person already set
Oct 28customer contact (raw)"as soon as someone steps into the conversation, Clara just takes the backseat… what's the trigger point if she wants Clara to then resume?"E8Hand-back: "Clara, take it from here", or the renter waiting on nobody for 15 minutes
Oct 28customer contact (raw)"she's only gonna know you left a voicemail if you mark record communication or you put a note… to avoid you guys both reaching out on the same thing"E3Card notes and logged calls are read before every touch; nothing else can see a call
Nov 1Session records49 tours since Sep 2, 5 moves, one staff move through Clara (renter told nothing); moves made in AppFolio never reach Clara; no way to hand a tour to another agentE7PMS moves and reassignments flow into the same chokepoint (PR 2); the staff-move page covers the ask and the hand-off

7. How often each door is used (Situs, real data)

Counted from Situs's own records: the AppFolio guest-card dump (Jan 1 to Sep 1, 2026; apartment buildings, 658 cards; all property types in parentheses), the message mirror (Sep 29 to Nov 2) and the live window since Clara went on (Oct 29 to Nov 2, ten Clara threads). Renters as initials; doors in order of use.

DoorCountDenominator (window)How countedConfidence
E1 Staff booked the showing by hand390 of 390 booking events (507), about 11 a week; none by the system or Clara. 205 of 337 cards with a showing (61%) were born booked: the same person typed the card in and booked within five minutes, no earlier logged contact. Live: staff 4, Clara 1Booking events; cards with a showing (dump). Bookings (live)"Showing Scheduled" events with their actor; mirror "Your showing has been scheduled" texts, deduped by phone and slotHard
E3 Staff talked to the renter first429 of 658 cards (65%; 538 of 883) were typed in by staff, so the talk began before any feed could show the lead. Live: on 20 new lead threads the first message out was staff 6, AppFolio's auto-reply 6, Clara 5; staff wrote first on 1 of the 10 Clara threadsCards (dump); threads (live)First 2026 create event and its actor; mirror threads joined on person id and phoneHard (dump); tiny sample (live)
AppFolio's own automatic messages1,496 on apartment cards, about 43 a week: three to four per booked showing plus the inquiry auto-reply; 319 in the mirrorMessages (dump and mirror)Template text match on card notes and message bodiesHard
E7 Staff changed a showing after booking105 of 377 booked showings (28%; 135 of 489), about 3 a week: moved 39, reassigned 31, cancelled by staff 46 (28 of them never confirmed after AppFolio's request), confirmed by hand 26. Mirror: 11 moved notices, 15 cancelledBooked showings, by card and unit (dump)Showing Modified / Canceled / Confirmed with a staff actorHard
E8 Take-over, then hand-backLive: staff took over 2 of 10 Clara threads after her first message; Clara never wrote again after staff (0). Proxy: 80 of 577 cards (14%) bounced between a VA seat and an agent two or more timesThreads (live); cards with human messages (dump)Message order; sequence of who sent each human outbound messageHard (the two); estimate (proxy)
E4 / E5 Clara joins late: tour done or application in45 of 658 cards (7%; 103 of 883) were created by an application; 18 came back with a new inquiry after touring or applying. Had Clara been switched on Sep 1, 61 of 87 open active cards (70%) had already toured or applied. Live: 0 of 10Cards (dump); the Sep 1 snapshot"Created automatically via new rental application" notes, first 2026 create event onlyHard
E2 Renter booked on a listing site before anyone spoke0 showings without a staff actor. Tour requests before contact: Zillow "I would like to schedule a tour" on 31 cards, Zumper 3, Tenant Turner availability 6; 10 Tenant Turner cards booked by the agent with no logged outreach. Mirror: no renter text mentions self-bookingShowings and cards (dump); renter texts (mirror)Actor on Showing Scheduled; text match on activity and inquiry textHard zero; the requests are estimates

What the counts change: the import (PR 2) is the product at Situs, and a switch-on day is a mid-flow day (seven in ten open cards already past the tour), so phase 2 ships before anything renter-facing; staff moves are one booked showing in four, so PR 2b and the staff-move chain come next; listing-site import goes last. Caveats: AppFolio's confirm requests carry the agent's name and read as staff work; talk outside AppFolio is invisible, so "staff first" is a floor; the live sample is ten threads.

8. Risks and the double-message hazards

HazardHow it bitesAnswer in this design
AppFolio's own messages on Clara's showingsFede, Nov 2: AppFolio does ask the renter to confirm. The evidence says otherwise so far: the one Situs card Clara booked (Oct 31, tour Nov 2) carries no "scheduled" text, no "Showing Reminder" email and no confirm request by the time Clara's one-hour reminder had gone; its thread holds only Clara's texts. Staff bookings get the request 22 times in 23, 2.0–2.2 h before, under the assigned agent's name: the team's confirm habit is AppFolio's templateDesigned for both. Phase 2's Willows run books through Clara and watches the bench phone; until then AppFolio item 2 stays on at Situs and Clara's reminders stay as they are
AppFolio auto-cancel an hour outA Clara-booked tour the renter never "confirmed" to AppFolio would be cancelled under the team's name. Unknown: the toggle sits on a page the Clara AI user cannot open. Never seen: 0 auto-cancels in the 2026 dump, 90 unanswered requests still went on to "Showing Occurred", a DENY becomes "Canceled by Prospect", staff cancel the rest by handGo-live page item 3 goes off only when confirm-or-release is on; meanwhile a PMS cancel flows in as pms_auto_cancel: silent to the renter, host told once, re-offer through the cadence (yes/hold 3)
Clara's follow-up cadence after a staff bookingThe cadence's "tour booked" stop reads PropFlow tours only. Staff book in the PMS, Clara keeps texting the renter; when the cadence ends with no reply it marks the guest card inactive. Since Oct 29, 2 of the 4 staff bookings at Situs were on threads Clara had already texted. Suspicion, not reproducedPR 2's import trips the existing stop. Its replay checks every VA-booked Situs card for a Clara touch after the booking
A moved tour loses its remindersFound in code today, not yet reproduced (a suspicion until the replay says so): no schedule version is ever written, and a reminder leg that already fired returns for good, so a tour moved after its day-before reminder gets nothing for the new time (every move: Clara's desk, staff, PMS)PR 2b: the replay reproduces it first, then bump the version on every move and the legs re-arm
A renter confirms, then cancels, to AppFolioOn one Situs card the renter texted Confirm, then Cancel an hour later: AppFolio sent nothing, logged the showing as Occurred and emailed "Thanks for visiting" the next day; the host went for nobodyClara reads a cancel in any words (the existing classifier) and tells the host; the baseline to beat, not the target
Echo loopClara's own showing comes back through the sync as "staff-booked" and mints a second tour. Today her rows are told apart by actor name only, and a real Situs record stored her showing as actor kind staff, name "Clara AI"The drain stamps the showing id at write; import keys on it; slot match covers old rows
Imported tour that already happenedLink leg fires at once; the attendance gate says "send" two hours after the end; the walker re-sends off !applicationLinkSentAt for 7 days24-hour window in the one domain function both call (yes/hold 1)
Listing-site remindersTurboTenant and Tenant Turner remind on their own; Clara would make it tworemindersBy: 'site' quiet skip until the customer turns the site's off (yes/hold 4)
Tenant Turner bookings land in a mailbox we do not readBlind to most of them; Clara may still offer times. Size at Situs: 0 self-booked showings this year, 6 Tenant Turner availability requests, 10 Tenant Turner cards the agent booked with no logged outreachAsk the Situs org admin where they land (go-live page); PR 6 parses what reaches leasing@; the PMS self-schedule path (PR 2) covers Zillow/AppFolio bookings
A listing-site "showing booked" notice read as a tour requestToday the notice is classed tour_request; when its body names a day and time the tour pipeline can create an auto-confirmed tour and send Clara's confirmation on top of the site's. Reachable in code, no fixture, untestedPR 6 turns the notice into ShowingObserved before the tour pipeline sees it
Supervised modeImported-tour renter messages held for review; a hold that outlives the tourSame hold as any tour text: expires at the tour's start
AppFolio's post-showing email on Clara's showingsProven double: Clara-created showing 597 drew AppFolio's "Thanks for visiting" email (planning note of Oct 19). It is a company-wide setting ("send automatic emails to guest cards after showings"), not one of the five per-showing boxes, so the robot cannot untick it; at Situs it also went to a renter whose application was already inPR 7 is Clara's version; AppFolio item 4 goes off the day it is live. Until then a renter who replies to AppFolio's email is matched by address (PR 7)
Staff keep using AppFolio templates on Clara's cardsTwo voicesA habit, not code; the visible claim on the card after Clara's first message (Oct 16 rule)
Missing property on the PMS showingAn early return drops the import or the next step: send-application-on-attended.ts returns no_property; the team-update and staff-alert senders and the "which tour did you mean" resolver bail the same wayCompany-scope tour, host line to the company inbox (Nov 2 rule); the guards on this path go as touched, one PR each

9. PR cut and proof ladder

PRWhatKindLinesProof before merge → before on
1Tour fields (external, importedAt, hostPersonId if the staff-move PR 1 has not landed; source already exists), readers, the drain stamping the showing idStorage, no behavior change~300Byte-identical replay of every tour row at the three customers
2Adapter: showing activity → ShowingObserved; renter resolved from the card; import/upsert into a tour with source: manual | external; confirmed start; PMS move / cancel / assignee (proposed, rule H) / CONFIRM / recorded outcome into the existing chokepoints; trigger pms; silent-renter rule; host line by email; the no_property exit removedFix (staff-facing; closes "Clara never learns of it" and the cadence texting a booked renter)~580Replay of the 24 Situs staff-booked showings and every "showing canceled" line since Oct 20, plus the VA-booked cards checked for a Clara touch after the booking → Willows: a hand-booked showing becomes her tour, host emailed, calendar written, bench phone watched for AppFolio's text → sandbox company in Situs's shape
2bA moved tour gets reminders for its new time: bumpVersion: true, version passed to the start, the two reminder legs re-arm after a rescheduleFix, no switch~90Reproduce first: replay of October moves at Western Slope and Situs where the day-before reminder had gone out → Willows: move a tour after its reminder, the new slot gets one
3Renter messages on adopted tours: the "you're set" line, reminders, the two quiet skips, the 24-hour windowNew capability: company setting, default off~300Willows run with the setting on → on at Situs the day AppFolio item 2 goes off
4–5Confirm-or-release (sub-design): the "reply yes" reminder, the host line at 30 minutes, no cancelNew capability: setting tourConfirmBeforeDriving, default off (Fede, Nov 2 row 7)~220Willows → on at Situs, then AppFolio item 3 off
6Listing-site booked-showing parsers → ShowingObserved; the notice no longer enters the tour-request pipeline; remindersBy: 'site'Fix (a booking Clara ignores, or doubles, today)~300Replay of the 2026 TurboTenant / Tenant Turner booking emails → Willows → AppFolio item 7 and the sites' own reminders off
7Post-showing follow-up: thank-you + "how did it go?" in the first after-tour touch; replies to AppFolio's thread matched by sender address to the renter's conversationImprovement to live behavior, no switch~250Replay of attended tours → Willows → AppFolio item 4 off
8–11Staff moves and reassignmentAs cut on that page~1,670That page's ladder

Order for Situs: item 1 off now (4a is already off); PR 1–2 and the Willows run settle the AppFolio-confirmation question, PR 2b alongside; PR 3 with PR 4–5 retire items 2 and 3 together (a renter never hears two confirmations, nor none); PR 7 retires item 4; PR 6 last, for item 7.

Parked ideas (Nov 2 2026, Fede: no further work)

Found Nov 2, lines only (Fede: no unasked PRs)

Design B: Opus 5.5 (full design, click to open)

Proposed, pending review · Nov 2, 2026 · Opus designer · read-only research: nothing sent, no PR, no setting changed · AppFolio behavior read from real Situs cards on Nov 2

1. One-pager

1. Today Clara runs only the tours she booked herself. At Situs in 2026 that is 0 of 495 showings: staff or the VA booked every one in AppFolio.

2. Fix: the tour workflow can start at any point. Every step checks "already passed, or already done by someone else" before it fires.

3. New: showings booked in AppFolio or on a listing site become Clara tours within 15 minutes. She puts each on the host's calendar, reminds, and follows up after. She confirms only if AppFolio did not, and never introduces herself again.

4. Threads: when a person answered first, Clara stays quiet until the renter has waited 15 business minutes with nothing promised, then picks up where the thread is.

5. North star: all seven AppFolio automatic messages off. Lead nurturing is already off at Situs; three more settings and one team habit can go today; each other one goes the day its replacement passes a Situs replay and a Willows run.

PhaseWhat changesPRsProof rung
1. Fixes, no switchA tour Clara learns about late never gets an early step. A call or note staff log on the card counts as a teammate stepping in; AppFolio's automatic texts never do (if the suspicion in section 8 reproduces).2Replay of every open tour run: identical except the listed late-started runs; replay of 440 Situs confirm texts; Willows late-start run and a logged call
2. Showings booked elsewhere (company setting, off)Staff, VA and renter-booked AppFolio showings and TurboTenant bookings become Clara tours with the right host. Moves, cancels and reassigns follow. Each goes on the host's calendar and blocks the slot in her availability.3Read-only replay of 495 Situs showings, zero duplicate tours; Willows: book, move, reassign, cancel in AppFolio; sandbox company in Situs's shape
3. ReplacementsAfter-tour text for every tour. Replies to AppFolio's "Thanks for visiting" email reach Clara. Clara picks up staff-started threads when the renter waits (setting, off).2Replay of 266 post-showing emails and 47 Situs text threads; Willows
Sibling pagesConfirm-or-cancel; staff tour move acceptance; group email threads~10On their pages

Decide (yes / hold):

  • Ship phase 1 as fixes, no switch? Recommend yes.
  • Build phase 2 behind a company setting, default off, and turn it on at Situs after the Willows run? Recommend yes.
  • On a tour staff booked, Clara sends her own confirmation only when AppFolio's did not go, puts it on the host's calendar unless an event already sits there, and emails the host only when someone else booked it for them (a card note either way)? Recommend yes.
  • Clara asks a renter to confirm only where AppFolio does not: her own tours once a Willows run confirms what card 9022 shows (AppFolio sent nothing before the tour), and staff tours only when the confirm box was unticked. Otherwise she reads the CONFIRM or DENY reply? Recommend yes.
  • Clara picks up a staff-started thread after 15 minutes of renter waiting in business hours (5 after hours), as a setting, default off? Recommend yes.
  • Situs switches AppFolio's messages off in the order of the table below? Recommend yes.

North star: AppFolio's seven automatic messages, each replaced

Wording is AppFolio's own, from real Situs cards (October). Coverage counts Situs renters, not code paths: "live in code" is not "live at Situs". On the one Clara-booked card checked (9022), none of AppFolio's messages before the tour fired; its thanks email was not yet due. At Western Slope AppFolio did send that email, under Clara's name, for a showing we wrote (Oct 18).

AppFolio message at Situs (verbatim; 2026 count)Clara todaySitus coverage at 2026 volume, today → afterBuild nowProof rungOff at Situs when
1. Inquiry auto-response, within minutes of every inquiry, from the assigned agent, replies to that agent: "Thank You for Your Interest in 375 S. Depew St. … please reply to this email or call 303-789-3030 and press option #1 … We will also follow up with a call." 248 sent. Questionnaire: never seen on a card.live for new cards first reply within a minute, with times. But in renter text threads since Oct 20 she was first in 1 of 47 (staff median 9 min); the reason is unmeasuredNew guest cards: all (go-live page) → same, and renter replies reach her instead of one agent's inbox. Text threads: 1 of 47 first → the section 5 rule decidesNothingRunning at Situs (go-live page, Oct 30)Today
2. Showing confirmation, the same minute staff book (form boxes ticked by default). Text: "Your showing has been scheduled: 8654 E. Richthofen Pl. Denver, CO 80220 Fri 10/16/2026 2:30pm MDT -- IH Holdings Six LLC". Email titled "Showing Reminder": "A showing has been scheduled for you on … If you have any conflicts or concerns, please reply to this email or call our office." 525 texts. No later reminder exists.partial her own tours get a confirmation, a day-before and a 1-hour reminder (card 9022); staff-booked showings get nothing from her0 of 495 staff-booked showings → 495, plus two reminders AppFolio never sentPhase 2. Her confirmation goes only when AppFolio's did notReplay of 495; WillowsPhase 2 proven
3. Confirm ask, about 2 h before (7 of 7 recent staff-booked showings), logged under the agent's name: "Please confirm your showing: 8654 E. Richthofen Pl., Denver Today at 2:30pm MDT Must reply with CONFIRM or DENY by 1:30pm." Instant replies: "Your showing has been confirmed: …" and "Your showing has been canceled: …". 440 asks. Auto-cancel of unconfirmed: unknown (never seen on a card; Clara's AppFolio user cannot open that setting).missing no ask, no release; her 1-hour reminder is the only day-of touch0 of 495 asked by Clara → each tour asked once, by one senderConfirm-or-cancel (sibling page). Launch: ask; if silent 30 min before, email the host once; no automatic cancel. Read CONFIRM and DENY repliesReplay of 440; WillowsConfirm-or-cancel proven. Both auto-cancel states designed (section 8)
4a. Lead nurturing: 3 workflows, all drafts, none published; no leasing Realm-X flowsalready off Gap on our side: her follow-ups stop once a person has repliedAt most 11 of 47 text threads, the ones no person answered first (Oct 20 to Nov 1) → 47 of 47Phase 3 staff-thread pickupReplay of the 47Nothing to switch
4b. Post-showing email, about 23 h after (5 of 6 showings), even after the renter applied, from the agent: "Thanks for visiting 8654 E. Richthofen Pl. … 3 bd, 2.0 ba, 1,100 Sq. Ft. | $2,500 /mo … For more information or to apply, please contact us by responding to this email or calling us at (303) 789-3030." 266 sent.partial after her own tours: "How was your tour of <home>? We hope you loved it! If you're ready to take the next step, you can apply here: <link>". Never after an application. AppFolio's thanks email also follows her own tours (Western Slope, Oct 18), so those renters get both today. A renter's reply to AppFolio's email lands on AppFolio's thread (Fede: in leasing@), not hers; the reply join covers only replies reaching a mailbox she reads0 of 266 → every attended tour; replies answered on the thread they arrive onPhase 3: after-tour text for every tour origin; reply join. AppFolio still sends the application itselfReplay of 266; WillowsPhases 2 and 3 proven
4c. Showing survey: the tab exists, zero responses everlive in effect: the after-tour text asks how it went; the host gets the notes askNothing to loseNothingNone neededToday
5. Hand-sent templates: "thanks for your interest" texts (103 typed by staff) and the VA's "Send Showing Invitation": "We received your inquiry for … and just wanted to check what date and time …"live her first reply offers timesTeam habit, not a settingNothingNone neededToday (ask the team)
6. Per-agent alerts in each agent's My Settings (only an admin can read them)not needed the leasing inbox alert stays; tour notices email the host (Fede, Nov 1; being built)SameNothingNone neededToday
7. Renter self-scheduling: AppFolio's prospect-scheduled showings (setting not readable), Tenant Turner on every property, TurboTenantmissing she cannot see these bookingsAppFolio self-booked: 0 → all (they are AppFolio showings). TurboTenant: 1 booking since May 20 → read. Tenant Turner: blocked until we know which mailbox gets its bookingsPhase 2 (TurboTenant in its third PR)Replay; Willows with a forwarded samplePhase 2 proven; Tenant Turner after the mailbox is found

Stays on: the showing notice to current residents (ticked by default on the form) and AppFolio's application email.

2. The journey, with every way in

Clara can enter at any state. Numbers on the picture match the table.

New lead Talking Tour booked Confirmed Tour time Tour done Applied 3 1 2 if already confirmed 4 5 6copied late on email: any state conversation paused while a person has the thread; reminders keep going 8 Moved · cancelled · new hostby staff, in AppFolio or by text moved: back to booked 7
Way inClara doesSkipsTells the hostNever repeats
1. Staff or VA booked the showing in AppFolio, or told Clara it is bookedMakes it a tour with AppFolio's host (from a staff message, writes the showing first); puts it on the host's calendar unless an event already sits there; blocks the slot; reminds the day before and an hour before; after the tour asks how it went and sends the application linkHer confirmation when AppFolio sent one (the default); offering times; introOne email when someone else booked it for them (the VA booked 288 this way); a card note either wayAppFolio's "scheduled" text; AppFolio's confirm ask (she reads the reply)
2. Renter booked on a listing siteSame as 1, and writes the showing into AppFolioConfirmation (the site sent one), offering timesOne email: nobody on the team has seen itThe site's reminder, where the site still sends one
3. Staff answered firstWaits; takes over when the renter waits 15 business minutes with nothing promisedFirst-reply text, intro, questions already answeredNothingAnything a teammate already said
4. Tour already happenedApplication link if attended and not sent; notes ask if the card has no noteEvery step before the tourNotes ask, onceThe application, when AppFolio already sent it
5. Application already inAnswers questionsTour offers, follow-ups, application linkNothingAnything about applying
6. Copied late on an emailReads the whole thread; answers what she is asked; does what she is toldTeam talk; introOne line back to whoever askedA teammate's words
7. Staff moved, cancelled or reassigned a tour she bookedRe-times every step; host steps go to the new hostHer "moved" text when AppFolio already sent oneOld and new host: one email each (Fede, Nov 1)A second confirmation
8. Staff took the thread, then handed it backPauses conversation; resumes from where the thread isRe-greetingOne line on hand-backQuestions already answered

3. Temporal: one tour workflow from any state

Two parts. A start state in the workflow input, used only by the import (phase 2, behind its setting). And a catch-up check in every step, which is the fix: a late start, retry or replay skips a moment that has passed, and nothing new fires. So the workflow PR merges alone; its replay lists every open run that differs.

already passed or done by someone else: skipped Clara learns of the tour (staff booked it 3 h before) confirmation(AppFolio sent) confirm nudges day-beforereminder AppFolio asks at −2 h;Clara reads the reply 1-hourreminder host told"they're coming" start notes ask how was it +application link
Step (code)Started late todayAfter
Confirm nudges (Phase 1, tour-awaiting-confirm-nudges)Runs a cadence read even for a confirmed tourSkipped when the start state is confirmed or later
Booking confirmation (sent at booking, outside the workflow)Not reached by a late startStaff and listing-site tours: sent by the import only when the card shows no outside confirmation after one sync
Day-before and 1-hour reminders (runReminderTimer, runReminderT1hTimer)Already skip a passed momentSame; also skipped when the outside system already reminded
Confirm ask (on this page)Not builtClara-booked tours: on once a Willows run confirms card 9022 (AppFolio sent nothing before the tour). Staff-booked: off when AppFolio's box was ticked, the default; she reads the reply. Its "silent 30 min before" host email belongs to the sibling page
Host "they're coming" text at −30 (runHostConfirmNoticeTimer)Sends on the renter's yes; a late yes sends at onceSame; a CONFIRM reply to AppFolio counts as the yes
Staff check-in +30 and notes ask (runStaffCheckinTimer)Fires at onceSkipped if more than 2 h past at entry
Application link +60 (runAppLinkTimer)Fires at once, after attendanceOnce, if attended and AppFolio has not sent the application; skipped if the tour ended over 7 days before entry
Calendar write retry (runCalendarWriteRetry)RunsOutside tours: writes the host's event unless one already overlaps that slot (staff add showings by hand). Never moves or deletes an event she did not make. Host with no connected calendar: the slot is blocked in availability
Post-tour follow-ups (Phase 3)Park on a person-owned threadSame
ConcernDesign
Signals for outside changesReuse tourRescheduled and tourCancelled; add tourHostChanged {eventId, hostPersonId, at}. Host steps move to the new host; renter steps stay.
Idempotency: importConditional put on the outside id (appfolio:situsgroup:612), so two sync passes cannot make two tours
Idempotency: Clara's own showing read backThe drain writes the outside id on her tour; fallback match: same person, same home, within 30 minutes
Idempotency: outside changeeventId = ext:<id>:<hash of day, time, status, host>; the workflow's existing event dedup drops repeats
Idempotency: each sendExisting row stamps (day-before, 1-hour, application claim, host notice) and call-time activity keys; unchanged
VersioningOne patched('tour-start-at-state') read once at the top; old runs replay unchanged
StartWorkflow id stays the tour id; the import starts with signal-with-start, so a running workflow gets signals, never a second run
DelayAppFolio guest cards are read every 15 minutes today (adapter comments), so an outside showing reaches Clara within about 15 minutes. One showings report per account per tick keeps within AppFolio's request budget
FileChange~Lines (est.)
src/lib/temporal/workflows/tour-workflow.tsOptional startAt {state, origin, outsideNotices} input; marker; Phase 1 skip; catch-up call per step; tourHostChanged220
src/lib/temporal/workflows/tour-timers.tslegDueState(fireAtMs, nowMs, graceMs) → future / due / passed, and one grace per step40
src/lib/temporal/workflows/tour-skip-reasons.tsQuiet skips late-entry-passed, done-elsewhere6
src/lib/temporal/tour-client.tsstartTourAtState(), signalTourHostChanged()60
src/lib/temporal/activities/tour.tsHost steps and the calendar write read the host from the tour; the write first checks for an event already in that slot70
src/lib/data/types.tsTour fields in section 430
src/lib/domain/leasing/tour/outside-showing-import.ts (new)Upsert by outside id, echo guard, signals, card note300
src/lib/domain/person-picture/staff-touched-since.tsA call or note logged on the card counts as staff engaged; AppFolio templates never do60
src/lib/domain/calendar/check-availability.tsOutside showings count as busy for that host and home60
src/lib/domain/pms/guest-card-writer.ts + AppFolio adapterNeutral outside-showing read (section 4)190
agents/clara/lib/email/parse-lead-source.tsTurboTenant booking and reminder emails150

4. Data model

Core code reads only these neutral fields. AppFolio names stay in the adapter. Today's Tour.af field, an AppFolio name in core, becomes outside.

FieldValuesWritten byRead by
originclara · staff · listing_siteClara's booking; the importStart state, never-repeat rules, notices
hostPersonIdA person with a leasing role at the companyClara's booking; the import maps AppFolio's assignee to a person by role (proposed, rule H); else the company rotationHost steps, availability
outside.idProvider-prefixed: appfolio:situsgroup:612, turbotenant:<id>Adapter, parser, the drain after Clara's own writeEcho guard, change detection
outside.seenHashHash of day, time, status, hostImportChange → signal
outsideNoticesconfirmation · confirmAsk · reminder · afterShowing: what the outside system already told the renterAdapter turns AppFolio's automatic texts into neutral noticesNever-repeat rules
Boundary record (adapter output)OutsideShowing {id, personRef, homeRef, startsAt (with zone), minutes, status: scheduled | cancelled | no_show | completed | other, hostRef, createdByRef, updatedAt, confirmAsked: yes | no | unknown}AppFolio adapter; listing-site parsers. Today's card showing has no host, creator or update time; the adapter adds themThe import only
Thread link on the conversation{threadRef, kind: email | pms_text, joinedBy: copied | reply_to_pms_email | forward, members}Inbound email; mirrorSection 5 rules

A showing whose home does not map still imports at the company, in the company's time zone, and the host is asked which home. A missing property never drops it.

5. Who goes first, and joining late

At Situs, staff or the VA answered first in 36 of 47 text threads since Oct 20 (median 9 minutes). Clara keeps going first on new leads. Once a person has the thread, these rules apply. They extend today's follow-up check and first-touch decision; no second engine.

SituationClaraHer first lineToday
New lead, nobody has answeredspeak within a minuteFirst reply, as todayLive
A person answered first and the renter has not written sincequietNoneLive for replies (she stands down after a staff text) and follow-ups (the cadence ends for good). First reply: decided, only logged
Renter's newest message waits 15 min in business hours (5 after hours), no promise pendingspeak (setting, off)Picks up the thread's state. No intro, unless she writes from a number or address the renter has not seen: then one clause, "This is Clara with the leasing team"New (PR 7): the ended cadence becomes a wait that wakes on the renter's next message
Staff logged a call or note on the card, or texted Clara about it (Oct 14, 21, 28)quiet; reads it firstPicks up from the note; never re-offers what it says is doneNot a signal: the follow-up check reads only messages (fix: PR 1)
Staff promised something ("I'll send times tomorrow")quiet up to 24 h, then nudges that teammate, not the renterNone to the renterThe 24 h wait is live; the nudge is new
Staff said "I've got this one"quiet in conversation; reminders keep going unless staff say stopNoneNew: the staff text line books, moves, cancels and takes notes, but has no stand-down
Staff hand back ("Clara, take it from here")act, one line back to staffContinues from the thread's stateNew
A card a teammate made by hand (Oct 14: "likely is not at the beginning")Decided on the lead-source page: Fede asked on Oct 14 for one signal-based check, with who made the card as a signalNone until decidedFirst-touch decision only logged
Copied late on an emailSpeak, act or stay quiet by the group-thread rule (VA POCs page)Answers only what she was askedSibling page
Renter replies to AppFolio's automatic email (lands in leasing@ on AppFolio's thread)speak on that thread if no person replied in 15 minAnswers the question; application link if askedNew (PR 6)
AppFolio template sent under a teammate's name (CONFIRM/DENY, "scheduled")Not a person: never silences herNoneSuspected to silence her today (section 8; PR 1)

Proof: replay the 47 Situs threads. Count where Clara would have spoken; the bar is zero times within 5 minutes after a staff reply.

6. What Western Slope told us

Since September their staff act first, by hand: they book in AppFolio or by phone, call leads Clara is working, and own any thread they step into. Clara does not see it, so she starts over or repeats. Quotes are raw transcript lines; a speaker is named only where the transcript names one.

Date, whoWhat they said or didHow this design answersSource
Sept 9, JasonThe VA's habit: "hey, Kat, I just booked you a showing in an hour, let me know if you need to cancel it."Way in 1 tells the host the same way: one email when someone else booked itSep 9
Sept 16, Jason's mic (likely Kat)AppFolio's schedule-showing button "used to automatically put it onto my calendar. It's not."Way in 1 puts every adopted showing on the host's calendarSep 16
Sept 16, Jason's micAppFolio will send "a confirm or deny ... that's already happening"; it reminds "even after a showing ... It's weird"; "I set that up, I can turn that off"One confirm ask and one after-tour message per tour, from one sender (north-star rows 3 and 4b)Sep 16, later
Sept 16, JasonKat out: "let's just book it to Jonathan right now."Way in 7: a host change moves the host's steps and calendar event; the renter's steps stay. Finding the cover: VA POCs pageSep 16
Sept 21, Fede (our debrief)"a human went in and ... scheduled another tour for the same person that already had a confirmed tour."Same renter and home: the newer showing moves the open tour; the host hears once (section 8)Sep 21
Sept 22, said to Kat (transcript label: Jason)"you don't respond to the email if you see it at leasing, you wait to see Claire taking it." Then: "you're quicker than Clara."Clara answers new leads within a minute; when a person still answers first, section 5Sep 22
Sept 22, Jason; Jason's mic (likely Kat)Staff must "see what Claire has done ... pick up where Claire left off", "some of the most friction". "once I jump in, does she? She doesn't jump back in."Section 5: quiet while a person has it; back on hand-back or when the renter waitsSep 22, later
Sept 22, Jason's mic (likely Kat)"the two that I just answered to before Clara got to it ... I clicked schedule showing ... but it did not show up on my calendar."Way in 1: a Clara tour within 15 minutes, on the host's calendarSep 22
Sept 23 to 24Kat booked a renter's afternoon showing herself in AppFolio. Fede deferred detecting this until a second hand booking in AppFolio came within two weeks; the next on record is Oct 16 (below)Phase 2 is that deferred itemGo-live tracker
Oct 14, Jay's mic (Jay and Kat); Fede"I already scheduled it verbally with the person"; Kat "doesn't want to trigger Clara going all the way from the beginning"; "I already did the showing." Fede: "Either advance them to the stage or don't engage at all."The start state (section 3): the tour starts at booked or done, with no first stepsOct 14, later
Oct 14, Jay (shared mic)"Don't reach out to him like he's a brand new lead." On a hand-made card: it "likely is not at the beginning."No intro on a late join. Hand-made cards: the lead-source page decides (section 5)Oct 14, later
Oct 14 and 21, Jay's mic; Western Slope (speaker redacted)Clara texted to schedule "20 minutes after Kat just recorded that she had a phone call with her." Oct 21: Kat should call good leads herself, and Clara should not then ask "should I turn off your guest cart?"A logged call or note, or a staff text to Clara, counts as a person stepping in (section 5, PR 1)Oct 14, Oct 21
Oct 15 to 18, Kat and usKat asked Clara by text to book Tiffani; Clara's write failed; Kat made the showing herself; our by-hand re-send then made showing 597 beside hers. The double booking came from us. AppFolio then sent "Thanks for visiting" for both, one under Clara's namePhase 2 reads showings back; every write, re-sends included, checks the slot and the outside id first; message 4b goes off with phases 2 and 3Oct 19 inspection page (production timestamps)
Oct 19, Kat, by email"We always do a showing in person or virtual before we send them an application. We don't want people spending the money if they haven't seen it first."Application link only after the tour, for every tour originKat's email, quoted on the Oct 19 inspection page
Oct 20, KatMoved Spencer's tour to 9:15 by staff text; Clara's next notice still said 9:00Way in 7: every step reads the tour's current timeWestern Slope inspection, Oct 19 to 20
Oct 21, Western Slope (speaker redacted)The hand-off is "my big thing". "But if it doesn't make it into AppFolio, Clara has no way of knowing, period."Phase 2 and section 5: what staff do in AppFolio reaches Clara within 15 minutesOct 21, later
Oct 21, Western Slope (speaker redacted)"hey, Clara, I already scheduled this showing, can you just put it on the calendar with this person? And Clara reached out to schedule the showing."Way in 1 and the start state: she records it, puts it on the calendar, never offers timesOct 21
Oct 7 to 28, notesOct 7: "Now Clara's doing it." Oct 21 (speaker redacted): "Clara texting her and asking her for showing notes is a fantastic example of something that is working well." Oct 28 (likely Kat): "She texts me after every showing to ask me what notes to put in." Oct 14: asked again half an hour after Kat gave notes; Fede: "it shouldn't ask you again"Kept and extended to tours staff booked; skipped when the host already gave notes for that renterOct 7, Oct 14, Oct 21, Oct 28
Oct 28, Western Slope (speakers redacted)"as soon as someone steps into the conversation, Claire just takes the backseat"; "what's the trigger point if [Kat] wants Clara to then resume with that guest card". Two of them disagreed on whether whoever steps in owns it "maybe up until a certain point"Section 5's triggers: staff hand back, or the renter waits 15 business minutes with nothing promisedOct 28, later
Nov 1AppFolio refused Clara's showing because the host had no AppFolio access to that home; it was written unassignedThe host field maps AppFolio users to people; the import reads the host backProduction alert, Nov 1

7. How often each way in happens (Situs)

Way inCountWindow and source
Showing booked by staff or VA in AppFolio495 of 495Jan 1 to Sep 4, 2026; 884 guest cards, robot dump
AppFolio confirm ask sent (all logged under a teammate's name)440Same
Of all asks: renter confirmed · no answer, tour happened · DENY45% · 29% · 10%Same dump, 452 asks 2022 to 2026
Showing moved · cancelled by staff · cancelled by renter78 · 66 · 53Jan 1 to Sep 4, 2026, dump
Showing handed to another agent39 (35 cards)2026 to Nov 1; Fable inbox study
VA booked onto an agent's calendar2882026 to Nov 1; Fable inbox study
Staff or VA answered a text thread first36 of 47Oct 20 to Nov 1; Fable inbox study
Clara wrote in a staff-touched renter thread10 of 150Oct 20 to Nov 1; Opus inbox study
Teammate email to a renter, leasing@ copied, skipped by Clara72Oct 25 to Nov 1; Clara's log (234 such emails in 2026)
Showings staff booked in AppFolio since go-live42Oct 20 to Nov 1; Opus inbox study, unverified
TurboTenant "New lead!" emails · booked showings119 · 1May 20 to Nov 2; go-live page
Tenant Turner booking that reached leasing@12026; go-live page
Showing Clara wrote that got an AppFolio message: before the tour · after it0 of 1 · 1 of 1Situs card 9022, read Nov 2 (its tour was that morning, so the thanks email was not yet due) · Western Slope showing 597, "Thanks for visiting" under Clara's name, Oct 18 (inspection page)

Order by frequency: staff-booked showings first, then staff-first threads, then moves and cancels, then late email joins.

8. Risks and double messages

HazardWhat the renter would getGuardStatus
AppFolio confirms or asks on a Clara-booked showing (Fede's concern; the robot's "notify off" comment was unproven)Two confirmations, two confirm asks, or two after-tour messagesBefore the tour: on Clara-booked card 9022 AppFolio sent nothing. After it: AppFolio's thanks email did go, under Clara's name, for a showing we wrote at Western Slope (Oct 18). A Willows run checks both before her confirm ask goes live; if AppFolio asks, her ask stays off and she reads CONFIRM and DENY. The thanks email goes off at Situs with message 4bbefore: holds on 1 card · after: AppFolio sends
Auto-cancel of unconfirmed showings (state unknown)A tour released at the deadline, an hour beforeIf on: arrives as an outside cancel; no 1-hour reminder; host told once; renter offered the next time once. If off: nothing changesboth cases designed
Confirm asks logged under the host's name (440 of 440 in 2026)If the inbox mirror files them as staff, Clara goes quiet on tour dayReproduce on Willows first; if it reproduces, AppFolio templates become notices (phase 1)suspicion
A renter texts "Cancel" after "Confirm"AppFolio ignores it, logs the showing as occurred and sends the thanks email (card 9002)Clara reads the text as a cancel and tells the host; AppFolio's "occurred" is never attendanceDesigned
Replies to AppFolio's emails go to one agent's inbox (the auto-response replies to the agent; the thanks email comes from the agent with no reply-to; Fede: thanks-email replies land in leasing@)An answer only that agent seesThe reply join covers only replies that reach a mailbox Clara reads. Switching each email off is the full fix: message 1 today, 4b after phases 2 and 3verify where replies land
Import sees a showing before AppFolio's "scheduled" text is readTwo confirmationsDecide the confirmation one full sync after the showing is first seen, or read showings and texts in the same passverify which read carries the texts
Listing-site reminder (TurboTenant "Showing Reminder")Two remindersClara skips her day-before reminder on that tour until the site's is offDesigned
Clara's own showing read backA duplicate tourOutside id; fallback: same person, home, 30 minutesDesigned
Tenant Turner marks cards Inactive or Cold (851 times in 2026)Clara might stop on a live leadA listing site's status change is not the renter's decision; check which statuses stop herverify
No attendance on a staff-booked tourNo application linkUse the host's notes reply; else today's fallback (end + 2 h)verify
Staff book a second showing for a renter with an open tour (Sept 21: the VA did this at Western Slope)Two times and two sets of remindersSame renter and home: the newer showing moves the open tour and the host is told once; Clara cancels the older showing only if she made it. Different home: a second tourDesigned
Staff already put the showing on the host's calendar by hand (Sept 16: Bev "just looks at your calendar and she puts it on there")Nothing; the host would see two eventsNo write when an event already overlaps the slot; she never moves or deletes an event she did not makeDesigned
Rently at Western Slope (Oct 13, our team: showings booked "in AppFolio or rentally" don't come back; transcriber's spelling)A tour Clara never seesFind where its bookings land; then the same import as TurboTenantverify
AppFolio's showing notice to current residentsNone from ClaraStays on in AppFolio; Clara never sends oneBy design

9. PR cut and proof ladder

This page cuts seven PRs in three provable units. About ten more live on the sibling pages and are not re-cut here.

#PRKind~LinesProof rungUnlocks at Situs
1Who counts as a teammate: a call or note logged on the card does; AppFolio templates never do (that half only if section 8's suspicion reproduces)Fix, no switch140Replay of 440 confirm texts; Willows, with a logged callNothing to switch; protects tour day; no follow-up right after a staff call
2Tour workflow: start state, catch-up check per step, host-change signalImprovement, no switch; dark until PR 4 uses it380History replay of open runs: identical except listed late starts; Willows late startNone alone
3Neutral outside-showing read (host, creator, update time, status, confirm box) and tour fieldsNew capability, storage, dark420Read-only replay of 495 Situs showingsNone alone
4Import: new showing → tour; changes → signals; host's calendar (no write if an event is there) and slot; card noteNew capability, setting leasing.adoptOutsideShowings, default off600Willows: book, move, reassign, cancel in AppFolio; sandbox in Situs's shapeMessage 2; AppFolio self-booking (7)
5TurboTenant booking and reminder emails → outside showing (Tenant Turner once its mailbox is known)Same setting250Replay of the May 20 booking; Willows with a forwarded sampleMessage 7 for TurboTenant
6After-tour text for every tour origin; replies to AppFolio's emails reach her threadFix (reply join), no switch; staff tours ride PR 4's setting260Replay of 266 post-showing emails; WillowsMessage 4b
7Pick up staff-started threads after the wait: the follow-up check's "teammate answered" stop becomes a wait that wakes on the renter's next messageNew capability, setting leasing.pickUpStaffThreads, default off300Replay of 47 threads, zero collisionsMessage 4a

Referenced, not cut here: confirm-or-cancel (on this page; unlocks message 3), staff tour move acceptance (4 PRs, Proposed Nov 1), group email threads (3 PRs, VA POCs page). The staff-booked showings page, when it lands, owns PRs 3 to 5; whichever cut it settles wins.

Ladder for every unit: replay of real Situs records → Willows live run on AppFolio's test property → sandbox company in the centralized shape (new capabilities only) → Situs switches off the matching AppFolio message.

Dark-features register lines
Dark: leasing.adoptOutsideShowings | feature: showings booked elsewhere become Clara tours | proof: pending | turn-on: Fede
Dark: leasing.pickUpStaffThreads | feature: Clara picks up staff-started threads when the renter waits | proof: pending | turn-on: Fede
PropFlow Docs