Proposed — pending review · investigation only, no code changed · 2026-10-14, overnight pass to 2026-10-15
Current state of how a lead reaches Clara and when she replies and assigns herself, the Situs Group lay of the land versus Western Slope, the Jay Taylor case, and a proposed per-customer ramp gate. Two independent passes (Fable 5.1 and Opus 5.5), compared in section 8.
Contents
Five pieces of local work overnight, sections 16.1 to 16.5. Nothing shipped, no PR, nothing turns on. Headline numbers spot-checked against the result files.
In one breath: Situs needs one setting for Saturday. The reasoning layer is not worth building for "should Clara reply"; cheap rules beat it. It is worth building for follow-ups, where today's fixed timers land on a person a third to a half of the time and "wake and look" cuts that to one in ten. The alarm-clock seam already exists and the Temporal change is small and well-contained. The glass is empty at both customers until notes, activity and assignee flow fresh at every wake. Nothing shipped tonight; no PR was opened.
| Pattern | Confidence | Evidence | What it changes |
|---|---|---|---|
| One company setting (the source list) gets Situs to Saturday | High | 96 of 96 Zillow Rental Network cards system-created; four real cards walked (16.2) | Phase 0 = one PR of ~250 lines plus four ops steps |
| Fixed follow-up timers land on a person a third to half of the time | Medium. The year had no Clara in it, so no cadence ever stopped on a reply. In production, 65% of finished follow-up runs ended because the renter replied first and only 4.5% reached a second touch; but 58% of the 98 runs live right now are already past touch 1, so the quiet-lead group is growing since the early-October fixes | 1,252 wakes; 44% Situs, 35% Western Slope (16.5) | Phase 3 is the biggest customer-visible win |
| Four plain rules fix most follow-up misses without a model | High | 188 lone-greeting wakes, 74 of 74 under 12 h held (16.5) | Ship inside today's check, before any wake work |
| A model at intake is worse than the company default on hold-or-reply | High | 81% vs 95% Situs, 30% vs 59% Western Slope; typist lookup 66% (16.4) | No reasoning layer for intake; three cheap rules instead |
| A model at follow-up time is right 85%, and proposes better actions | High on the 85%; the 175 changed actions were listed, not scored | 175 wakes turned into showing, answer or application messages (16.5) | Phase 3's wake may change the action, behind the rules |
| The alarm-clock seam exists; the Temporal change is one call inside one activity | High | scheduled-wake merged Oct 14; 654 runs, 0 failed, 110 live (16.1, 16.3) | Phase 3 is 11 small PRs, 8 with no customer effect |
| The picture is empty at Western Slope and Situs | High (verified in code) | Notes import off everywhere; no assignee in the picture (16.1, 16.2) | Phase 1 before any decision can see Kat's call |
| The follow-up check is blind to AppFolio staff texts at Situs | Medium | Message sync listed as in progress; median staff text at 19 h (16.2) | Connect the message sync before Saturday or accept week one |
Decisions for Fede this morning, one line each, recommendation first:
Phase 0 shipped: per-company list of lead sources Clara answers. Merged (PR #20019) and proven live at Willows on Oct 15: with the list set to Zillow Rental Network only, a Zillow card got Clara's reply and assignment (card 232), a staff-typed TurboTenant card was left alone (card 233), the list was then restored. Evidence: proof comment. Situs can be set on Saturday with one command; new companies start with an empty list (Clara answers nothing until a list is set).
Two notes for the builders: the source-list setting must show on the company page, which is Gera's settings lane, so a heads-up goes to Smith on the bridge before that PR. And section 9 line 5 is sharpened by 16.4: the Western Slope default is no longer "reply to every staff-typed card" but "reply unless the typist's own history says hold".
Today Clara answers and takes over every new AppFolio card at a live company, whoever typed it. That was decided on Sept 30. It fits Western Slope, where almost every card comes from a listing site. It does not fit Situs, where most cards with a known creator are typed by a person (21 of 33 since Sept 29; by label, about 450 of 1,189 all time). Whether that person had already talked to the renter is not measured; Situs said on Oct 13 that it is the norm. The Jay Taylor double-contact happened at Western Slope on Oct 9, and nothing shipped since would stop it today.
| Finding | Number |
|---|---|
| Western Slope cards since Sept 29 → Clara replied and assigned herself | 42 → 29 |
| …of which typed by staff already in contact (the two double-contacts) | 2 |
| Situs cards since Sept 29 → Clara acted on | 64 → 0 (off) |
| Situs cards all time typed by a person, by label (TurboTenant, Facebook, Affordable Housing, Drive By, referrals) | about 450 of 1,189 |
| Situs source labels our code recognises | Zillow, Website, Apartments.com, Zumper, Realtor.com; not TurboTenant, Facebook, Affordable Housing, Go Section 8 |
Was removing the creator check a mistake? Partly. Right to stop using "who typed it" as the rule; wrong to refuse any "a human already has it" check in its place. Section 6.
Knowledge gaps: no, Clara could not answer most Situs renter questions today. Of 507 real questions in a year of Situs cards, about a fifth are answerable now, up to a third wait only on the calendar, and nearly half need facts the Situs knowledge base does not hold. Section 12.
One event, two robots. Every new AppFolio guest card our sync sees fires one "new lead" event. Two workers act on it on their own: one writes Clara's first email, the other assigns the card to Clara inside AppFolio. Both run the same checklist. Nothing on that checklist asks who created the card or whether a person already owns it.
flowchart LR A[New card in AppFolio
any source, any creator] --> B[Sync copies it
about once a minute] B --> C{Checklist} C -->|company off| X[Nothing] C -->|our own card echo| X C -->|imported at onboarding| X C -->|arrived before go-live| X C -->|already applied| X C -->|Clara already talking
and card has no message| X C -->|passes| D[Assign card to Clara in AppFolio
Supervised: still assigns · Off: refused at the writer] C -->|passes| E[First email] E --> F{Leasing mode} F -->|Live| G[Sent] F -->|Supervised| H[Held for a reviewer] F -->|Off| X
| Check on the list today | What it looks at | Stops a staff-typed card? |
|---|---|---|
| Company live switch | One yes/no per company | No |
| Our own card coming back | Cards Clara herself created (calls, texts, email leads) | No |
| Imported at onboarding / arrived before go-live | Timestamps | No |
| Already applied | Rental application exists | No |
| Clara already talking | Only Clara's own conversations and tours; a staff call or email is invisible. Skipped entirely when the card carries a renter message | No |
| Who created the card | Still recorded on every card (System vs a staff name), no longer checked since Sept 30 | Was yes, now no |
| Card already assigned to a person | Written in code, never called | Would be yes |
| Lead source label | Not consulted on the guest-card path at all. A company setting still gates the email lane only | No |
| "Reply, wait or skip" first-touch decision (added Oct 10) | Creator, staff notes, teammate messages the renter received, listing source. Log only: its answer is written to a log line and the email is sent anyway; its 10-minute wait on hand-made cards waits for nothing | Would be yes; today no |
| "Stop, wait or send" before each follow-up (added Oct 10) | Tenancy, opt-out, closed card, a teammate answered, a staff promise under 24 h. Enforced, but only for follow-ups, never the first email or the assign | Follow-ups only |
Three things worth knowing about the assign step. It runs before the email, not after. It ignores Supervised: Clara takes the card in AppFolio while her message is still held for review. (Off is honoured: the writer refuses every AppFolio write for a building whose Leasing is off.) And it overwrites whoever owned the card; the receipt only records the previous owner after the fact.
Other ways a lead arrives. Listing-site emails (Zillow, Apartments.com, Rent., Zillow's relay) go through a separate email lane that recognises senders, not sources, and is gated by a per-company lead-source setting. Phone calls and texts create cards that Clara herself owns. There is no "create a guest card" button in PropFlow. A new listing site we have never seen still gets answered if it also drops a card in AppFolio, because the card path does not branch on source. A new email format we cannot parse falls through to ordinary email triage, so it may still get a generic reply; only an unparsed Tenant Turner email raises an error line.
Correction to the premise: this happened at Western Slope, not Situs. Clara is still switched off at Situs and has never replied to or assigned herself a Situs card.
| Step | When, Mountain |
|---|---|
| Jay Taylor emails Arturo M. (a hotel's HR team had referred him), per the email Jay later pasted into the card notes. The card did not exist yet | Tue Oct 7, 6:00 PM |
| Arturo replies: limited English, prefers texts, wants the cheapest studio or room near Telluride | Wed Oct 8, 4:17 PM |
| Jay creates the guest card by hand at Northridge Apartments, source typed as "Madeline", and starts adding notes | Fri Oct 9, 7:17 to 7:19 PM |
| Our sync copies it; creator recorded as "staff: Jay Taylor"; no one assigned | 7:20 PM |
| Clara assigns herself in AppFolio | 7:20 PM |
| Clara's first email offers a 2-bed at $2,000 and a 3-bed at $2,650 with self-guided tours, and promises a lockbox code | 7:21 PM |
| Jay pastes Arturo's earlier email into the card notes, two seconds after Clara sent | 7:21 PM |
| Fede pastes the card into a session; Arturo's follow-ups are frozen the next day with the "a human has this" hold | 7:23 PM |
The card passed every check on the list because the only check that would have stopped it, "a person created this", was removed on Sept 30. Jay's name was on our record the whole time. Clara wrote from the card's inquiry message, which a staff-typed card never has, and did not read Jay's notes. The same shape happened once before: a card Kat Barker typed on Sept 29 got a reply and an assign within two minutes. Of 42 new Western Slope cards since Sept 29, Clara replied to 29; the two staff-typed ones are the only two where a person was already in contact.
What shipped after it (Oct 10): the card reader now returns the notes and the creator; a "reply, wait or skip" decision runs before the first email, with a short wait on hand-made cards; and a "stop, wait or send" check runs before each follow-up. The first-email decision only records what it would have done; the email still goes out. So as of today a second Jay Taylor card would get the same email and the same assign. The follow-up check is real: once a teammate has answered, Clara's later nudges stop.
Fede, Oct 9: "one of the best examples of Clara not having the full context, and sending an email that conflicts with what was sent by the staff."
Since Sept 29 Situs got 64 new cards (21 by a named staff member, 11 by the system, 28 with no creator recorded); Western Slope got 42 (4 by staff). The labels are exactly as AppFolio stores them. "Staff" means a named person typed the card; "System" means a listing site created it.
| Source label | Situs, since 9/29 | Situs, all time (1,189 cards) | Western Slope, since 9/29 | Who creates it | Do we recognise the label? |
|---|---|---|---|---|---|
| Zillow Rental Network / Zillow | 15 | 249 | 14 | System | Yes |
| TurboTenant | 9 | 135 | 0 | Staff | No |
| Website / Web | 7 | 139 | 4 | Mixed | Yes |
| No Source Recorded | 9 | 110 | 6 | Mixed | n/a |
| Facebook (five staff-named variants) | 5 | 102 | 0 | Staff | No |
| "Afforable Housing" (sic) | 6 | 74 | 0 | Staff | No |
| Drive By | 2 | 64 | 0 | Staff | As walk-in |
| Phone / call | 2 | 10 | 5 (Clara's own calls) | Staff at Situs; Clara at WS | Yes |
| Go Section 8 | 2 | 2 | 0 | Staff | No |
| Referrals and agencies (Lorraine's Referral, Housing Connector, Urban Peak, 2nd Chance Center, Elevate Recovery, Brother's Redevelopment, Colorado Housing Search, Ananeo, TikTok, Craigslist, Zumper, Realtor.com, Show Me The Rent…) | 5 | long tail | 0 | Staff | No |
| Apartments.com / Rent. / Zumper / Realtor.com | 3 | about 17 and 18 for the first two | 5 | System | Yes |
| Uloop / Madeline | 0 | 0 | 5 | System (Madeline: staff) | No |
What this says. Western Slope is a listing-site shop: most cards come from Zillow or another site, made by the system, and Clara answers them. Situs is a hand-typed shop: most cards with a known creator (21 of 33 since Sept 29) are typed by a person, with labels that say a Facebook message, a TurboTenant inquiry, a walk-by, a phone call or an agency referral came first. Turning Clara on at Situs with today's checklist would have her email and take over almost every one of those, including the ones a person just talked to.
Phone calls. Situs staff do log some phone leads as cards, but few: 2 of 64 by label plus one more by its notes. Whether Clara should follow up on those is an open question in section 10.
Correction (Oct 14, after Fede's note): an earlier version of this page said we had never read Situs's email. That was wrong. We read it once, on Sept 1, through the one-time AppFolio extract: 93,656 emails with full bodies, 32,309 texts, 1,355 notes and 883 guest cards for 2026, measured and posted that day. What that pass showed: 313 cards got only an instant auto-reply, the median first human reply took 5.1 hours, 154 cards (17%) never got a human reply, 592 emails went out from cards, and 13% of cards arrived after hours and 7% on weekends. That is the strongest evidence behind the nights-and-weekends recommendation below.
What that pass did not give us, and what no later pass has: a split of the inbound inbox mail by listing site. The extract holds the email AppFolio logged against a person's record, not the raw leasing@ inbox, so a TurboTenant or Section 8 lead that a staff member read in Gmail and retyped into a card appears only as the card. The mailbox (leasing@thesitusgroup.com, Google) has been connected since Sept 29 and Clara is set up to send from it, but live Gmail reads are still paused pending the paid Google security audit or Situs's Workspace admin marking our app as trusted. So the "arrives by email" column below is still inferred from what staff paste into cards. Next pass to settle it: re-run the Sept 1 extract's email set (the 2026 dump on Fede's Drive) with a sender-domain count, which needs no Google audit.
| # | Opportunity | Volume per 30 days | What it takes |
|---|---|---|---|
| 1 | Have AppFolio email us every new card and set Situs's lead-source setting, like Camellia | about 45 cards (24 in the last 16 days) | The AppFolio notification path Camellia uses; not re-verified here. Situs flips one AppFolio setting. Turning it on is Fede's call |
| 2 | TurboTenant inquiry email → we create the card → Clara replies | about 26 (9 in the last 16 days) | New parser, plus a way to receive the mail: cheapest is Situs forwarding TurboTenant mail to our per-company inbound address, which avoids the Google audit (inferred, not tested) |
| 3 | AffordableHousing.com / GoSection8 email → card | about 8 | New parser, same mail-receiving question. One such email already lands in AppFolio on its own |
| 4 | Zillow direct, the Western Slope pattern | about 0 since Sept 30 (was 21 the month before) | Parser exists. Only worth it if Situs still lists outside AppFolio; it looks like those moved to AppFolio's Zillow feed |
| — | Facebook, TikTok, drive-by, referrals, agencies | about 20 | Cannot be hooked. A person is already talking to them |
One tell that these are hand-typed: TurboTenant, Affordable Housing, Zillow-direct and Drive By cards are rarely created after hours (5 to 8% of 974 inquiries this year), while Zillow Rental Network, Realtor.com and Zumper run 43 to 63%. Facebook variants sit in between (12 to 36%).
Short version: we can see almost everything we would want, but only one place tells us who created a card, and that is the robot reading the card's activity log, not the reports feed and not email.
| Signal | Where we get it | How good | Already stored in PropFlow? |
|---|---|---|---|
| Who created the card (System vs a staff name) | Robot, activity log ("Guest Card Received" vs "Guest Card Created by Jay Taylor") | Reliable since the Sept 28 fix; the reports feed has no such column | Yes, on every card |
| Source label | Reports feed per card; robot per inquiry | Free text as typed. AppFolio's own "No Source Recorded" is on 64 of 1,040 Western Slope cards; PropFlow's prospect page shows "no source" for about 880 of them because it hardcodes the source instead of reading the card's label (a display bug, separate finding) | Yes, mapped to our buckets |
| Who the card is assigned to | Reports feed and robot | Reliable | Yes, refreshed every sync |
| Staff texts and emails sent inside AppFolio | Robot message read | Reliable for messages sent through AppFolio only | Yes, every 1 to 2 minutes |
| Logged notes and activity (calls logged, "email sent") | Robot and reports feed | Only what staff choose to log | Partly |
| The renter's own words | Robot; listing-site email | A listing-site card carries a message; a staff-typed one never does | Yes |
| Listing-site email arrival | Mailbox | Seconds, free; proves the lead came from a site | Yes |
Not available anywhere: a yes/no "this came from a listing site" flag (we build it from creator = System plus a renter message plus a site-named source); calls or texts staff make from their own phones; a listing id on the card; any lead webhook from AppFolio. TurboTenant and Facebook arrive only as a label a person types, so there is no email we could hook unless Situs forwards those notifications to a mailbox we read.
We have been on both sides of this in four weeks. The creator check went in on Sept 18, got patched seven times, and was removed on Sept 30 at Fede's ask. The Jay Taylor email went out nine days later.
| Date | What changed | Why, in Fede's words |
|---|---|---|
| Sept 18 | Creator check added. Clara replies only when the card's first history line is "Guest Card Received" by System. Staff-typed cards are left alone. Source labels were rejected as the signal: the Sept 18 write-up counted 772 staff cards and 381 listing-site cards carrying the same labels (its query is not on record). | "no this is a hack" (on guessing from the label). "The one exact signal is the creation event: created by System versus created by a person." |
| Sept 21 to 29 | Seven patches: test properties, the creator stamp arriving late (wait and retry), a staff hand-over counts as consent, cards with no creator name stop parking forever. | Sept 28, on a call: "they'll bring over that and type it in manually. So they already had that conversation… so those ones, Clara skips them." |
| Sept 29, night | A Western Slope Zillow card stalled about an hour: the robot could not read the "created by System" line while its login was locked out. | "Turn it on" (Western Slope set to also take listing-site emails) |
| Sept 30, 3:46 AM UTC | Fede asks to drop the check. | "removing the logic of like it has to be a guest card created by an admin… if we say the staff is gonna stop manually adding guest cards could we get rid of that completely and just reply to all guest cards all emails all lead sources" |
| Sept 30, 8:45 AM UTC | Creator check removed. Every new card gets the first email, whoever created it, no setting, live for every company. The lead-source company setting was removed the same day, reverted two minutes later, and its reland was closed; it still exists on the email lane. | "i dont want old paths around at all. one engine period." That night the session proposed a softer version, "skip when staff are already talking to the prospect," and the memory note records a flat "no": no skip logic of any kind. Reasons given: staff would stop typing cards by hand, the creator read had just stalled a lead, and one rule for every company. The Oct 9 case is exactly what that softer check would have caught. |
| Oct 1 | Non-syndicated Zillow Rentals emails: Clara creates the card herself, then replies. Caused duplicate cards at Western Slope on Oct 8, since fixed. | — |
| Oct 9 | Jay Taylor case. | "freeze this. Because it's already handled by a human." |
| Oct 10 | Reader returns notes and creator; reply/wait/skip decision before the first email; stop/wait/send check before each follow-up. | — |
| Oct 13 | Situs call. Their side: "anything from TurboTenant or Zillow would be like a no-brainer"; "I would just say Zillow Network. And TurboTenant would be the easiest ones to have you turn on." Renters already "feel like they're getting contacted from like 3 different places." | "I would recommend the ones that are automatic, from Zillow or from anything that's syndicated." On a Facebook lead a teammate had answered: "now we kind of have like 2 conflicting." |
| Oct 14 | Fede to Gera: a ramp-up mechanism to pick lead sources, start with Zillow only, manually created leads never reply, personal Facebook out of scope. Gera: "zillow and TurboTenant?" | "Today we reply to all by default. Might want switch to do it incrementally." |
Partly, yes. Both passes landed on the same answer independently.
Two mechanisms, kept apart because Fede's rules treat them differently: a permanent fix with no switch, and a new per-customer setting that defaults closed.
flowchart LR
A[New card or lead email] --> B{A human already
has it?}
B -->|yes: person assigned, or staff wrote
to the renter before Clara| X[Leave it alone
no email, no assign]
B -->|no| C{Is its source on this
company's list?}
C -->|all, or listed and on it| D{Leasing mode}
C -->|not listed, or unknown| Y[No action
one 'new source seen' line a day]
D -->|Live| E[Assign + first email]
D -->|Supervised| F[Draft held; assign on approval]
D -->|Off| X
Honest test first: at 7:20 PM, Jay's card had no assignee, no logged outreach (his earlier email predates the card) and empty notes; the notes landed two seconds after Clara sent. A check that only reads what is on the card at first sight would not have stopped it. So the rule has three parts:
| Piece | Proposal |
|---|---|
| Where | One company-level setting, settings.leadScope, replacing the old lead-source setting that still lives on the email lane (delete-before-add). Never per property. |
| Shape | { mode: 'all' } or { mode: 'listed', sources: [...] }. A source is a named key we define in code as how it arrives plus the exact labels and senders it matches: zillow_network (System card from Zillow, or a Zillow email we parse), turbotenant (card labelled TurboTenant, any creator, or a TurboTenant email once we parse one), apartments_com, rent_com, website, and so on. Calls and texts to Clara's own line are never scoped. |
| Default | A company created after this ships starts listed with an empty list: live, but answering nobody until Fede picks. Western Slope and JP&Co get all written at migration so nothing changes for them. The turn-on script refuses to make a company live with an empty list unless all is set on purpose. |
| Unknown sources | A label or sender not on the list gets no action, plus one "new source seen: TurboTenant, 9 cards" line per company per day in the alerts channel. That line is the "supported lead sources" register Fede asked for. |
| How Fede sets it | A back-office script, no UI: set-lead-scope <company> listed zillow_network,turbotenant. Every change is ledgered and shows on the dark-features register. |
| With Supervised | The mode says how Clara acts (held or sent); the scope says on what. Both compose: "Supervised, Zillow only" is one line. |
Today Clara takes the card in AppFolio while her message is held for review. Proposal: Supervised assigns when the reviewer approves; Live assigns at once; Off already never writes. This reverses Fede's Sept 22 "assign as soon as we know" ruling for the Supervised case only, so it is his call (section 9).
Situs staff do log some calls as cards (2 of 64 by label). Recommendation: leave them alone by default; the caller already has a human. A later option for a centralized team, off by default: follow up after 24 hours if the card's log shows no staff outreach. Replying at once is the Jay Taylor case again.
| Order | Source | Why | Proof before turn-on |
|---|---|---|---|
| 1 | Zillow Rental Network cards AppFolio creates on its own | The only path proven end to end at a real customer; 14 of 64 Situs cards in the window; both Fede and Situs named it first | Situs sync pause lifted with Gera and new cards seen within a minute; a Willows run where a staff card is skipped and a System card is answered, then the same under Supervised; cards 3004 and 1823 replayed through check A and skipped |
| 2 | TurboTenant cards (staff-typed today) | Situs's second-largest source and their own "no-brainer"; the rollout page already promises it | Only after check A is enforced and proven on Situs-shaped cards: a TurboTenant card with a logged staff text is skipped, one without is answered |
| later | Website, Zumper, Realtor.com, Apartments.com cards | Automatic, low volume | Same Willows run per key |
| never by default | Facebook and TikTok variants, drive-by, referrals and agencies, phone cards staff typed | A person is already in the conversation; Situs said personal Facebook is out of scope | — |
| not yet | "Afforable Housing", Go Section 8 | Voucher rules not in the knowledge base | Section 12 replay |
Two independent passes, then one rebuttal round. Opus 5.5 wrote its pass without seeing Fable's; the census and code findings were shared with both.
| Question | Fable 5.1 | Opus 5.5 | Outcome |
|---|---|---|---|
| Was the Sept 30 removal a mistake? | Partly: right for Western Slope's shape, wrong for Situs's; the loss was "no skip logic of any kind" | Partly: same split, first argued from a 56% retype figure | Agreed. Opus withdrew the 56% as a current number (4 of 42 since Sept 29) |
| A permanent "human already has it" check on email and assign | Yes | Yes | Agreed |
| What the ramp gates on | Named source keys, each defined as arrival plus exact labels | "Automatic only" plus a list of email senders | Opus conceded: "automatic only" can never cover TurboTenant at Situs, where an assistant retypes the cards. Condition added: a key that accepts staff-typed cards ships only after check A is enforced |
| Default for a new company | Listed, empty list; "all" written on existing live companies | Absent means "all" | Opus conceded, and added the guard: the turn-on script refuses live plus empty list unless "all" is explicit |
| How to build check A | Enforce the existing Oct 10 decision, both workers | New check | Opus conceded and added the assignee re-check at the write. Opus also proposed dropping the 10-minute settle; the Jay timeline shows the settle is what would have caught his notes, so it stays (Fable held) |
| Supervised holds the assign | Yes | Yes | Agreed; Fede's call because of the Sept 22 ruling |
| Phone-call cards staff typed | Leave alone | Leave alone; later a 24-hour follow-up option for centralized teams | Agreed |
| First Situs source | Zillow Rental Network, then TurboTenant under check A | Zillow Rental Network; TurboTenant only after an email parser | Opus conceded: the parser is a separate automation; the card path works under check A |
One caveat Opus held and Fable accepts: the "two of three Situs cards are typed by a person" figure is measured before Clara is on at Situs, so it is the expected shape, not a result.
Six yes/hold lines. Recommendation first in each. Re-checked Oct 14 after the mailbox correction in section 4: none of the five leaned on the "never read" claim; the Sept 1 extract numbers (17% of cards never answered by a person, 13% after hours, 7% weekends) make line 4 stronger, and line 5 still holds because live Gmail reads remain paused.
Not on this list, already clear under standing rules: the stale comments and dead gate get deleted with A.
What Situs's knowledge base holds today: three company entries (office address, walk-ins by appointment, how residents pay), office hours, and deposit and fee amounts copied from listings at 20 of 52 buildings. No building has a policy written down; every amenity list is empty.
| Of 507 renter questions in a year of Situs cards | Share |
|---|---|
| Clara can answer today | 97 (19%) |
| Blocked only by the missing calendar ("can I see it") | 169 (33%) |
| Blocked by missing or partial knowledge | 241 (48%) |
By source, the share needing a missing fact is highest where the renter already talked to a person: referrals (19 of 22), TurboTenant (35 of 50), housing programs (22 of 31). Zillow is the most answerable: 26 of 88 non-tour questions answerable, 46 missing.
| # | Gap | Blocked | Example | What staff actually answered (first draft of the fact) |
|---|---|---|---|---|
| 1 | Application and screening: decision time, documents, income, co-signers, fee, background | ~50 | "status of our application?" | "2 to 3 days"; "any photo ID incl. passport or matrícula"; "co-signer applies separately"; "no application fee" at Lampliter and Carr (staff replies, unconfirmed by the client) |
| 2 | Move-in money and specials: holding deposit, how to pay, current specials | 37 | "how many weeks free?" | "deposit holds only if approved"; "pay by phone, option 2"; "up to 6 weeks free spread over 12 months" |
| 3 | Building facts: utilities, accessibility, parking, laundry, unit details (mostly Carr Street Flats) | ~34 | "monthly utilities? parking included?" | "electric about $30 to 75"; "parking free unless reserved"; "laundry on the first floor"; "there is an elevator" |
| 4 | Pets: allowed, types, limit, pet rent, support animals. Deposit known at 8 buildings, the rule at none | 30 | "Do you allow pit bulls?" | "$300 refundable deposit + $35 a month"; "no dogs unless a support animal" at one DU home |
| 5 | Move-in process, keys, lease terms (sublease, start dates, month to month) | 23 | "sublease process?" | "written approval; subtenant applies"; "no month to month for new tenants" |
| 6 | Tour logistics, not the calendar: where to meet, how to get in | 19 | "just parked, where do I meet you?" | "building 4 upstairs"; "brown building behind the big lot" |
| 7 | Vouchers and Section 8, by building | 16 (+53 cards from housing programs) | "Section 8?" | "Yes" at some buildings, "not for this home" at others |
| 8 | "Please call me" hand-off rule | 9 | "please call me" | None; this is a routing rule, not a fact |
Zillow specifically. 245 Zillow cards, 159 questions; 71 of them are only "can I see it" (calendar). The rest Clara mostly handles (availability, rent, application link) except pets, deposits and move-in cost, co-signers at the DU student homes, application fee (staff replies say none at Carr; Emerson has a $26 fee on record), accessibility. Quickest win for a Zillow-first ramp: a company-level pet rule, co-signer rule, application-fee rule and deposit rule, plus a Carr Street Flats fact sheet.
What onboarding still owes. Connecting the calendar would unblock up to a third. The larger half is the company policy questionnaire (screening, pets, vouchers, deposits, specials, lease terms) plus about ten building fact sheets, led by Carr Street Flats, Barcelona, Lampliter, Aspen Leaf and the DU homes. Staff replies in the export already hold first-draft answers for about 120 questions; the client still confirms each one, per the knowledge-base writer rules.
Rent and availability count as answerable, but with the Situs sync paused since Sept 29, any live answer needs the pause lifted first. Outputs with renter names stay local under the corpus runs folder for Oct 14 and were not pushed anywhere.
Proposed, pending review. Fede, Oct 14 evening: no hardcoded "wait 10 minutes for a staff-typed card". Read every signal on the card, decide fast, and keep the per-company ramp list inside the same decision. One engine, called at intake and again before every send.
flowchart LR A[Card or inquiry event
from the PMS] --> S1[Signals already in our mirror
creator · source · renter message
assignee · status · age · hours
company mode · ramp list] A --> S2[Signals that need a card read
notes · activity log
texts, calls, emails logged
showings · known person] S1 --> G{decideLeadAction} S2 --> G G -->|REPLY| E[First email, assign,
then the whole machine] G -->|HUMAN_HAS_IT| H[Stand down.
Watch; help later if asked] G -->|OUTSIDE_SYSTEM| O[Stand down.
A person is already talking] G -->|SKIP| K[Nothing: applied,
inactive, duplicate, pre-go-live] G -->|undecided| R[Reasoning layer reads
notes and messages, then picks] E -. before every follow-up .-> G
| Signal | Where it comes from | At first sight? | What it tells the gate |
|---|---|---|---|
| Who created the card | Activity log: "Guest Card Received" by System vs "Guest Card Created" by a named person (robot read; not in the reports feed) | Usually; "unknown" is a legal input | System = a site or the website sent it. A person = someone already met this renter, by phone, referral, drive-by, or retyped an email |
| Renter message on the inquiry | Card inquiry panel | Yes (System cards) | Something to answer. Staff-typed cards almost never have one |
| Source label → source key | Card and reports feed | Yes | Arrival shape and the ramp-list match. Facebook, Drive By, Referral, phone = a human channel |
| Assigned user | Card and reports feed | Yes | A person other than Clara owns it |
| Staff touch already logged | Activity log and comms log: text, call, email, note, showing by a human actor (not the Auto-* events) | Needs the card read; cheap | The strongest "human has it" signal, at any age of the card |
| Notes | Card notes | Needs the card read | Free text for the reasoning layer: "spoke with her Tuesday", "admin card, no outreach", "showed 2841 today" |
| Known person | Our mirror: same email or phone on an earlier card or a lease | Yes | Current tenant, past applicant, or a returning lead; changes the opening, or stops it (tenant transfer) |
| Status and stage | Card status, application and showing events | Yes | Applied, inactive, showing already held: never start at step 1 |
| Age vs go-live, time of day | Our mirror | Yes | Backfill guard; after-hours cards are where Clara adds the most |
| Company mode and ramp list | Company settings | Yes | Off, Supervised, Live; which source keys are open at this customer |
| Today | What it decides | After |
|---|---|---|
| Shared eligibility check in the first-email worker | Clara live, own echo, backfill, pre-go-live, applied, Clara already engaged | One decideLeadAction(inquiry, asOf) in the leasing domain, returning outcome plus the reasons and the signals read. The first-email worker, the self-assign worker, and the follow-up engine all call it; nothing sends without it. Every decision is stored on the inquiry, so a bad call is replayed with the harness below and fixed in the function, never with a button. |
| Same check in the self-assign worker | Same list; assign still ignores Supervised | |
| Oct 10 first-touch step | reply, wait, skip; computed and thrown away (log-only) | |
| Oct 10 follow-up step | stop, wait, send; enforced | |
| Dead "assigned to a person" gate | Nothing; no caller |
Scales past these two customers: every property manager has the same split, syndicated and website leads that arrive on their own versus referrals, walk-ins and phone calls a person already owns. The source keys are defined by arrival plus label, not by customer, and the ramp list is a per-company setting, not code. The only customer-shaped thing is the default for "a person typed it and nothing is logged yet", and that comes from data.
Today's design starts every lead at step one and runs to a booked tour or silence. That is the Camellia shape, and it breaks at scale: plenty happens person to person, off the recorded lines. Today's Western Slope call (Jay, Kat, Jason with Fede, Gera and Sean) gave four real cases:
| What happened | What Clara did or would do today | What a co-worker does |
|---|---|---|
| The general contractor sent a driver-by to Kat's cell; she talked, booked and held the showing. No card exists yet. | If Kat texts Clara to add the card, Clara starts at step one and tries to book a showing that already happened. | Kat texts "showed him 566 Placer at 2, notes: … send the app". Clara finds or creates the card, logs the showing and notes, sets the stage to "showing done", sends the application, runs only the post-showing reminders. |
| An administrative card created so an application can be pushed (Lauren Jayne, Pomona Park unit 300). Correction, Oct 14 9:30 PM from session 009's records: she is a prospect, not a current tenant. One AppFolio card with two September rent.com inquiries that ended not interested; Clara emailed at 2:19 PM today; her application arrived at 4:24 PM. AppFolio's own Transfer Tenant task covers moves between properties except across different owner entities, which is likely why Jay made a card by hand. | Clara emailed to schedule a showing. | The facts on the card already say "application in flight": a staff-created card with no renter message, a past not-interested inquiry, and an application that lands two hours later. Stage inferred from those facts is "applied"; stand down. A note convention ("admin, no outreach") is the fallback, as a fact added to the card, not an instruction to Clara. |
| Kat phoned a lead 20 minutes ago and logged the call. | Clara texts to set up a showing. | The call is a human touch on the card: HUMAN_HAS_IT. Clara helps on request (send the app, book the tour Kat agreed) instead. |
| A manual card from years ago gets a new automatic inquiry (Jay's point: cards belong to people, inquiries to a moment). | A rule on the card would block the new inquiry. | Every decision is per inquiry, with the person's history as a signal, never as a block. |
Fede's framing (Oct 14, ~9:15 PM): this is a general capability, never a customer rule. The stage is inferred from facts on the record. Staff add facts (a note, a logged call, a showing), never instructions to Clara. One decision runs before every send.
The mindset: a new employee in AppFolio opens the guest card, reads the activity log, the notes and what has already been sent, and only then decides. Clara does the same, at intake and again every time a follow-up timer fires. Rules first, for the cases that must never go wrong; then the model reads the whole block as a person would and chooses: proceed, hold, or do something different.
flowchart LR T["Timer fires
(24h, 72h, ...)"] --> H["Hydrate: one context block
card · activity log · notes
every text, call, email · tours · stage"] H --> R["Hard rules
applied / assigned / human touch / asked to stop"] R -- "rule held" --> X["stop or wait, logged"] R -- "no rule" --> M["Model reasons over the block"] M --> P["proceed as planned"] M --> D["send something different"] M --> W["hold, say why"]
Where today's code already is, and where it is not (read on main, Oct 14; nothing changed):
| Fede's picture | Built today | Gap |
|---|---|---|
| One context block with everything a human sees | Yes, mostly. The "person picture" reader already gathers the threads (texts, calls, emails), tours and their outcome, tenancy, every inquiry with its card status, who created the card, and the notes and activity-log rows synced onto the inquiry. | Only what the sync has imported. The live AppFolio card is not re-read at send time, so a note typed five minutes ago is invisible until the next sync. |
| Wake at the timer, re-read, then decide | Yes. Every follow-up send calls one stop / wait / send check that reads the picture fresh at fire time. | Rules only, no model pass. Four stops (resident, asked to stop, card closed, teammate answered), one wait (a staff promise under 24 h), else send. Times out after 8 s and fails open to send. |
| First outreach reads the block too | Half. The first-touch decision runs over the same picture. | Log-only since Oct 10. It decides reply, wait or skip and writes it down; the email goes out regardless. Section 13 makes it enforce. |
| "Do something different" when context changed | No. The gate's answers are stop, wait or send. | The follow-up writer gets a short "prior notes" string for one personal detail; it never sees the staff thread, the activity log or the stage. A follow-up cannot become "saw Kat showed you 566 Placer, here is the application". |
| Rules plus a model that reasons | Rules exist and are tested on the harness. | No reasoning layer anywhere in the lead path. The Temporal schedule (24 h, 72 h, ...) is fixed; the model only softens the words. |
What this changes in the design above: item 4, the reasoning layer, gets a precise job. It is one call, at intake and at every timer, over the same block the rules read, and it returns one of four: proceed, hold with a reason, stand down, or a changed action (send the application, confirm the showing, answer the open question). The rules keep veto power; the model never overrides a hard stop. Its answers are logged beside the rule's answer so the harness can replay a year of cards and show where the two disagree. The schedule stays as the alarm clock, not as the decision.
Temporal stays. It is solid and centralized, and it keeps every timer, retry and action it runs today. What changes is one thing: the workflow stops sending the message itself from a hard-coded template. At the timer it hands back to the core Clara loop. Clara wakes up, reads everything that happened since she last touched the lead, and decides: proceed, hold, or do something different. Not a setting; it applies to every customer. Leasing follow-ups first. Renewals and maintenance follow-ups follow the same pattern later, because people interject there too and we follow up blindly today.
flowchart LR
subgraph today["Today"]
T1["Temporal timer"] --> S1["Workflow activity
composes and sends"]
end
subgraph after["After"]
T2["Temporal timer
(alarm clock)"] --> C["Core Clara loop
hydrate · rules · reason"]
C --> P["proceed"] --> D["same send door"]
C --> H["hold / stand down
(logged, timer moves on)"]
C --> X["changed action"] --> D
end
Where Temporal sends on its own today (observed on main, Oct 14): twelve activities compose and send messages from inside the workflow: prospect outreach, prospect re-engagement, renewal, maintenance comms, collections chase, post-tour chase, tour confirm nudge, promise, PM action reminder, mass comms, turnover, tenant confirmation review. Leasing is prospect outreach and re-engagement, where the stop/wait/send check already sits; that is where the seam goes first. The rest keep sending as today until each is moved, one at a time, with its own replay.
Proof before anything turns on (Fede, Oct 14, ~10:30 PM: "we better make sure whatever new thing works as well as what we have"). The Temporal permutation harness pins each workflow's observable behavior as committed goldens and grades a refactor mechanically: unchanged, fixed defect, regression, or new behavior. Checked on main tonight: it covers tour, renewal, pipeline and countersign. It does not cover prospect outreach or re-engagement, the two leasing workflows the alarm clock would touch first. So the order is fixed:
Order of work once Fede says go (each a small dark PR, none opened before his yes): (1) the gate from section 13, enforced at intake, over the existing picture; (2) re-read the live card at send time instead of the last sync, and fail closed to "hold" instead of open to "send" when the read fails; (3) give the follow-up writer the whole block, not a notes string; (4) the reasoning call, logged beside the rules first, deciding second, once the harness shows it agrees with staff on a year of cards.
Choices for Fede, with a recommendation: (a) staff slot a lead in by texting or calling Clara, and the stage is also inferred from the log — recommended, it is already how Western Slope works with her; (b) a note convention on the card ("admin, no outreach") as the fallback for Situs-style teams that live in AppFolio; (c) a stage picker on the PropFlow lead page, later, under Gera's settings lane.
Fede, 10 PM: "start with architectures, prototypes, harnesses; tomorrow morning give me findings with confidence, what went wrong, what worked; then we decide." Five pieces of work, all local, results folded into this page as each lands:
| # | Work | What it answers | Lands as |
|---|---|---|---|
| 1 | Architecture pass (Opus 5.5) | How the gate is one slice of the platform vision v2 and the PMS-conversations architecture; every earlier place this vision was stated; one vocabulary; the three biggest design risks. | Landed: section 16.1 |
| 2 | Situs minimum slice (Fable 5.1) | The smallest chain of dark PRs that lets Situs control which lead sources Clara answers, against the code as it is. No hours gate: nights and weekends is the phone line. | Landed: section 16.2 |
| 3 | Prototype: reasoning at intake | On the cards rules cannot decide, how often a model call would match what staff then did within the hour. Two postures: hold-only vs changed action. | Landed: section 16.4 |
| 4 | Prototype: wake-and-look follow-ups | At 24 h, 3 d and 7 d, how often "look first, then decide" beats today's fixed cadence, and how many blind follow-ups would land on a lead a person was already working. | Landed: section 16.5 |
| 5 | Temporal deep study | Architecture, every workflow and what it sends, 30 days of production runs, the exact seam for the alarm clock, the switch and fallback design (options with a recommendation), regression risks ranked, the proof plan through the permutation harness. | Landed: section 16.3 |
Morning shape: one findings table on top (pattern, confidence, evidence, what it changes), then the Situs slice, the cohesion map, the alarm-clock seam with its switch, and the decisions Fede asked to make in the morning. The seven yes/hold lines in section 9 and section 14 stand; nothing is re-asked tonight.
Headline: at Situs, a staff-typed card is a person's work: 80% get a staff text within 2 minutes of being typed, 92% within 10. At Western Slope the same wait finds almost nothing (40% at 10 minutes, 18% never), because their staff retype Zillow leads they already answered in the Zillow inbox, which AppFolio never sees. So no single wait fits both; the default for "a person typed it and nothing is logged" is per company, and the gate re-reads the card at send time anyway. The cards Clara is for are the automatic ones: at Situs a Zillow Rental Network card waits a median 19 hours for a human and 13.5% never get one.
Local harness, no PR, no CI, aggregates only. Situs window Sept 1 2025 to Aug 31 2026 (1,024 cards). Western Slope window Sept 1 2024 to Aug 31 2025 (964 cards; the 2026 cards were pulled without their activity log, and that year is distorted: their Zillow Rental Network feed was typed by staff from Nov 2024 to Aug 2025 and is automatic again now). Coverage: every row above 99% (activity log present, creation event found, timestamp parsed). Self-check with a planted card and a planted control passed. Files: gate_harness.py, coverage.md, mapping.md, results.md, results.json in the session scratchpad.
P1 = a staff-typed card counts as "a person has it". P2 = only a logged staff action counts.
| Reply | Human has it | Handled outside | Skip | |
|---|---|---|---|---|
| Situs, P1 | 24.9% | 35.8% | 27.6% | 11.6% |
| Situs, P2 | 52.5% | 8.2% | 27.6% | 11.6% |
| Western Slope, P1 | 29.6% | 51.5% | 10.9% | 8.1% |
| Western Slope, P2 | 72.3% | 8.7% | 10.9% | 8.1% |
| Source | Cards | Reply | Human has it | Outside | Skip | Median minutes to first staff touch | Never touched |
|---|---|---|---|---|---|---|---|
| Zillow Rental Network (automatic) | 96 | 100% | 0 | 0 | 0 | 1,138 (19 h) | 13.5% |
| Rent.com, Realtor, Zumper (automatic) | 86 | 95–100% | 0–5% | 0 | 0 | hours | low |
| Website | 117 | 52% | 15% | 0 | 33% (applied) | 200 | 17.9% |
| Zillow, plain label (staff-typed 87%) | 145 | 5.5% | 86.9% | 0 | 7.6% | 1 | 2.8% |
| TurboTenant (staff-typed 100%) | 105 | 0 | 100% | 0 | 0 | 1 | 1.9% |
| Affordable Housing / Section 8 (staff-typed) | 86 | 0 | 96.5% | 0 | 3.5% | 1 | 4.7% |
| Facebook, referral, drive-by, phone | 294 | 0 | 0 | 95–100% | 3–5% | 1 | 2–4% |
| Shared application link | 52 | 0 | 0 | 0 | 100% |
Reading it: every staff-typed source at Situs is touched within a minute or two of being typed, because the card is created as part of sending the first text. The automatic ones wait hours or days. That is the gap Clara fills, and it is exactly the Zillow Rental Network first-source call in section 9.
Among staff-typed cards, the share with a first staff touch within N minutes (cumulative):
| N | 0 | 2 | 5 | 10 | 30 | 60 | 4 h | 24 h | never |
|---|---|---|---|---|---|---|---|---|---|
| Situs (651 cards) | 28.6% | 80.2% | 88.5% | 92.5% | 94.3% | 94.9% | 96.2% | 96.9% | 2.2% |
| Western Slope (603 cards) | 23.1% | 36.0% | 37.5% | 39.6% | 43.8% | 45.6% | 53.6% | 66.2% | 18.1% |
| Sources open | Situs P1 | Situs P2 | Western Slope P1 | Western Slope P2 |
|---|---|---|---|---|
| Zillow Rental Network only | 9.4% (96 cards; 13.5% of them never got a human) | 9.4% | 1.2% (distorted year) | 4.6% |
| + plain Zillow | 10.2% | 19.9% | 1.6% | 41.0% |
| + TurboTenant | 9.4% | 17.8% | 1.2% | 4.6% |
| Sources automatic in practice (≥90% System) | 17.6% | 22.2% | ||
| All listing sites by label | 18.8% | 38.3% | 27.6% | 69.0% |
| Everything | 24.9% | 52.5% | 29.6% | 72.3% |
Cards from Sept 29 to Oct 14 where the robot stamped the creator: Situs 33 agree, 0 disagree (TurboTenant, Facebook, Affordable Housing, referrals, drive-by all typed by staff; Zillow Rental Network and Website by System). Western Slope 12 agree, 11 disagree, and 6 of the 11 are Zillow Rental Network cards that are automatic now and were typed by staff in the 2024–25 window. The source mapping holds; one production label (a person's name) falls to "other".
Objective: Clara stops replying to everything by default. Nothing goes to production tonight. Each phase ships dark, is proven on the ladder, and turning on at a customer is Fede's call. This draft gets sharpened as the Situs slice, the two prototypes and the Temporal study land.
| Phase | What Clara can do after it | What gets built | Proof | Size |
|---|---|---|---|---|
| 0. Must-have Situs ready | Answers only the lead sources a company has turned on; never talks over a card a person visibly has. | One company setting, the source list, inside the shared intake both robots call (PR 1, the only one Saturday needs); then the narrow "a person has it" check from creator kind and AppFolio assignee, deleting the dead gate (PR 2, before the list grows). | Unit with planted defect; byte-identical replay of Western Slope's real cards; Willows live. | 2 to 3 small PRs |
| 1. Fill the glass | Sees what a staff member sees: notes, activity log, assignee, raw source, fresh at every wake. | One per-company feed for card notes, activity and status at a sane cadence, no row to press; assignee and source key added to the picture; decisions logged on the richer picture. | Replay a year of cards: the log-only decision vs what staff did. | 3 to 4 PRs |
| 2. One decision | One answer at intake and before every send: act, record, wait, or hand to judgment. | Merge the first-touch and follow-up rule sets into one decision; enforce it at the first email and the assign (today it is log-only); one failure posture; the prospect-outreach adapter pinned in the permutation harness first. | Harness diff reads "unchanged" on every golden; replay table clean. | 3 to 4 PRs |
| 3. Alarm clock for leasing | Follow-ups wake Clara instead of sending a template; she looks first, then proceeds, holds, or does something different. | First the four follow-up rules inside today's check (lone teammate text under 12 h, renter wrote back to a teammate, showing booked, application out). Then prospect outreach and re-engagement call the existing wake seam; the wake reads the picture and may change the action; shadow mode first; the per-company switch with a one-write kill switch; a failed wake skips the touch and alerts. | Shadow log agrees with the replay; Willows; sandbox company in Situs's shape; supervised week. | 4 to 6 PRs |
| 4. Judgment and stage | Handles the messy middle: a showing already held, a card made for an application, a lead a person just phoned. | Three cheap rules first (per-company typist lookup, batch typing, holidays: the prototype shows they beat a model on hold-or-reply). The judgment step only decides what Clara says when a renter wrote something, behind the rules, log-only first. A stage on every inquiry, inferred from facts; staff add facts by text or call. | Prototype grades from tonight set the bar; planted-leak test at zero before note text reaches the model. | 4 to 6 PRs |
| 5. Same pattern elsewhere | Renewals and maintenance follow-ups look before they send. | Each workflow repeats phases 2 and 3 on its own: pin, shadow, flip. | Its own harness goldens and replay. | Per workflow |
Phases 0 and 1 can run in parallel; 2 depends on 1; 3 depends on 2; 4 depends on 1 and 3; 5 after 3 is proven at one customer. The four follow-up rules from 16.5 do not wait for 2 or 3: at Western Slope they land in today's check right after phase 0, proven by the same replay; at Situs once the message sync is on.
Three findings that matter in the morning. (1) The alarm seam already exists: a timer that wakes Clara's loop with an event and no pre-written text was merged today, with one caller, the after-tour check-in; prospect follow-ups are "not wired to this yet" and the wake reads the thread only, not the person picture. (2) Clara hydrates from an empty glass at Western Slope and Situs: the picture holds her own thread plus the card's creator and status; card notes and activity rows arrive once, behind a per-company import that is off everywhere, and the assigned user is not in the picture at all. The gate is inert at both customers until that feed is on. (3) Every idea on this page already has a home on another page and none is wired end to end; the right next PR is "the alarm reads the picture", not a new engine.
Verified by this session on main: the wake function and its single caller. Reported by the pass, not re-checked here: the notes-import switch state and the missing assignee.
| Word | Means |
|---|---|
| person picture | everything known about the person, built fresh at each wake ("hydrate") |
| alarm | a Temporal timer whose only job is to wake the loop for one person |
| tick | a poll on a PMS list that files events and never wakes Clara (session 006's page) |
| decision | hard rules with a veto, then the judgment step: act, ask, record or wait |
| judgment step | the model pass inside the decision, logged before it acts (this page said "reasoning layer"; the vision page uses that phrase for something else) |
Gate outcomes in that vocabulary: reply = act; a person has it = record, then wait; outside the system and skip = record; undecided = the judgment step.
flowchart LR
classDef built fill:#d8f0d8,stroke:#2e7d32;
classDef partial fill:#fff3c4,stroke:#b8860b;
classDef legacy fill:#f8d7d7,stroke:#a33;
classDef proposed fill:#ffffff,stroke:#666,stroke-dasharray: 5 5;
subgraph DOORS["Doors"]
CARD["AppFolio card sync"]:::built
TICK["AppFolio inbox tick, Willows only"]:::partial
MAIL["Listing and inquiry email"]:::built
LINE["Clara's line: text and call"]:::built
STAFF["Staff text Clara"]:::built
end
NOTES["Card notes and activity: once at arrival, import off everywhere"]:::partial
FD["Front door: one event per wake"]:::partial
subgraph CLOCK["Temporal = alarm clock"]
T["Durable timers and retries"]:::built
end
TPL["Template rendered in the workflow: about 15 senders"]:::legacy
W["Alarm seam (scheduled wake): tour check-in only"]:::partial
TH["Agent turn over the thread only"]:::built
subgraph LOOP["Core loop"]
H["Hydrate: person picture"]:::partial
R["Hard rules with veto"]:::partial
J["Judgment step, log-only first"]:::proposed
H --> R --> J
end
SEND["The activity's own send code: safety screen, door resolver, send gate"]:::built
REC["Decision recorded on the lead, replay harness"]:::partial
CARD --> FD
TICK --> FD
MAIL --> FD
LINE --> FD
STAFF --> FD
FD -->|"new lead"| H
NOTES -.->|"proposed: fresh at every wake"| H
T -->|"today, most senders"| TPL --> SEND
T -->|"alarm"| W
W -->|"today"| TH --> SEND
W -.->|"proposed next PR"| H
J -->|"act or ask"| SEND
J -->|"record"| REC
J -->|"wait: set next alarm"| T
Green = built and live. Yellow = partial or switched off. Red = the old way. Dashed = proposed.
Drop the new decision function name and say "one decision, the two rule sets merged"; add the first-reply text and the tour check-in wake to the call-site table; say the stop/wait/send check runs on three leasing senders, not every send; cite the alarm seam as built with prospect follow-ups as its next caller; add a step 0, fresh card notes, activity and status at each wake; add the assignee and the raw source key to the picture; rename "reasoning layer" to "judgment step"; state one failure posture; name what this page does not own (tick and door resolver: session 006; send gate: Gera; notes classifier and picture builder: their rows); do not make today's 10-minute wait on hand-made cards a rule; do not promise note text to the model until the leak test passes.
Full pass with file and line citations: session scratchpad, pass2-opus.md.
One setting is enough for Saturday. A per-company source list, enforced inside the one eligibility function both the first email and the self-assign already call. Today a live company answers and assigns every new card, any source, any creator; the only company gate is the live flag. With Situs set to Zillow Rental Network only, the "who typed it" question never arises: all 96 Zillow Rental Network cards in the harness year were created by the system, and every staff-typed card carries another label. No hours gate anywhere; the Saturday-night and Tuesday-morning cards get the same answer.
| PR | Concern | Kind | Lines | Proof | When |
|---|---|---|---|---|---|
| 1 | Per-company source list (absent = all, so every existing company is byte-identical on merge; new companies start empty; the live flag refuses to flip while the list is unset). Raw AppFolio label matched to a fixed set of source keys. Sits inside the shared intake, after the "applied" check, so the email and the assign cannot drift. | New capability, company setting | ~250 | Planted defect (a "Facebook Add" card eligible goes red); replay Sept 29 to Oct 14, Western Slope and JP&Co byte-identical; Willows live; sandbox company in Situs's shape | Tonight-ready, the only PR Saturday needs |
| 2 | "A person already has it": assignee set and not Clara's seat; in listed mode a staff-typed card is a person's (unknown creator passes). Deletes the dead gate, its reasons and the stale headers. | Fix, no switch | ~200 | Planted defect; 30-day Western Slope replay with every touched card marked; Willows | Before the list grows past Zillow Rental Network |
| 2b | Assignee on the person picture, so first-touch and follow-up rules can stop on "a person owns this card" | Fix | ~40 | Unit, replay | With PR 3 |
| 3 | Enforce the Oct 10 reply/wait/skip verdicts in both consumers; delete the log-only wrapper and the 10-minute wait | Fix, no switch | ~150 | Planted defect, replay, Willows | Next, not Saturday |
| 4 | Re-check the assignee at the moment of the assign write | Fix | ~80 | Unit, Willows | Next |
| 5 | Fold the old email-lane lead-source setting into the new list; migrate Western Slope | Delete-before-add | ~200 | Email-lane replay | Later |
Four real Situs cards walked through the slice (list = Zillow Rental Network, Live): a Zillow Rental Network card received by the system Saturday 7:37 PM, no renter message, unassigned, staff's first text 40 hours later: reply, email and assign within two minutes. A TurboTenant card typed by "Assistant Lead" Wednesday 10:06 AM with a staff text the same minute: nothing, one log line. A TurboTenant card typed by Courtney with "sent you the link to apply" two minutes later: nothing. A Zillow Rental Network card Tuesday 9:45 AM with a renter message, staff called 5.5 hours later: reply, identical to Saturday. About 93% of Situs cards carry no renter message, so reply must not require one; today's code does not, and section 13 of this page will be corrected to match.
Ops steps before Saturday, not PRs: resume the Situs sync (Gera) and let the backlog settle as not-live skips; set the list; confirm Clara's AppFolio seat on all 52 Situs buildings (a missing seat parks every assign while the email still sends); flip the live flag early in the day, because the go-live floor compares calendar days and a 5 PM flip answers that morning's cards.
Three things most likely to bite at Situs that the slice does not cover:
Left out on purpose, and why Situs can go live without it: reasoning over notes (Zillow Rental Network cards arrive with none), a stage per inquiry and live card re-read (a system card starts at step one and the first email is the whole Saturday job), the TurboTenant key (needs staff touches visible or the email parser), Supervised holding the assign (Situs starts Live per the plan). Said plainly: Jay Taylor's Western Slope card is not caught by this slice; only the follow-up stop covers that shape.
Not checked tonight: whether the Situs email lane, the notes import switch, or Clara's seat are set in production. Full pass with file and line citations: session scratchpad, pass2-fable.md.
Smaller change than feared, with one real hazard. Today's leasing follow-up is not a fixed template: inside the workflow, one step asks a narrow model prompt for the words, then sends. The change is that this one call becomes a wake of Clara's loop through the seam merged today; timers, quiet hours, reply signals, the send-once guard, consent and the touch counter all stay exactly as they are. No workflow logic changes. One number changes: the send step's 60-second limit becomes about 4 minutes, because a wake can take two. The hazard is a double send if a wake times out and a retry runs beside it; the fix is the longer limit plus the send claim staying ahead of the compose, proven by a planted double send going red in the harness.
Production, last 30 days, read-only from Temporal Cloud:
| Workflow | Completed | Terminated | Failed | Timed out | Running now |
|---|---|---|---|---|---|
| Prospect outreach (leasing follow-ups) | 654 | 97 | 0 | 0 | 98 |
| Prospect re-engagement | 242 (+716 continued on a new reply) | 14 | 0 | 0 | 12 |
| Tour | 412 | 0 | 0 | 0 | 36 |
| Renewal | 329 | 322 | 24 | 0 | 12 |
| Maintenance comms | 0 | 0 | 9 | 211 | 135 |
How often a follow-up actually goes out (200 of the 654 finished runs read): 180 sent no follow-up at all; 130 ended because the renter replied, 122 of them before any follow-up; 23 ended on a stop condition (merged, deleted, applied, tour booked, home gone). Of the 98 runs live right now, 57 are past touch 1 with two or more sent, so newer runs send far more. The hidden number is silent skips: across every attempted touch, 73 were skipped for no consent, 33 because the text step did not send, 22 for opt-out, leasing off or company not live, 17 for no mailbox, 11 because the lead had already advanced. Any redesign of the follow-up decision sits behind those gates; consent is the biggest one.
Leasing follow-ups never failed in 30 days; every non-completion was a termination (prospect deleted, Fede's manual cleanups, the Oct 2 "stop post-call follow-ups"). No retry storms anywhere. 110 live runs are the whole population a bad deploy could hit. Half of all timers in a real run are quiet-hours holds, so a wake that ends at 7:58 PM matters. Renewal (322 terminated, 24 failed) and maintenance comms (211 timed out) have their own problems and need their own look before they become "later" domains.
The switch and the fallback, options with a recommendation:
| a. Company "follow-up writer" setting | b. Workflow version marker + global flag | c. Shadow only | |
|---|---|---|---|
| How | The send step reads a company setting each touch: today's path (default) or Clara's loop. Kill switch = one write that sets every company back. | A version branch in the workflow picked by an env flag. | The wake runs beside today's writer; its decision and words are logged; today's words still go out. |
| In-flight runs | Pick it up at their next touch, no replay risk. | Only new runs; old ones stay old for up to 33 days. | No customer effect. |
| Rollback | One write, next touch. | A deploy, and old runs keep old code anyway. | Nothing to roll back. |
| Fede's rules | Passes: new capability, default off, on the company page, turn-on is Fede's, deleted the week it is proven. | Fails: env flags are banned, and the code itself says the version marker is not a switch. | Passes: a log line, not a switch. |
Recommendation: c, then a. Shadow first, diffed locally on the subscription over captured touch contexts plus a small production shadow (about 30 turns a day, tools off so it can write nothing a customer sees). When the diff is clean, add the company setting, off by default. Delete it the week it is proven everywhere. One ruling for Fede in the morning: when the wake fails, (1) skip that touch and alert, (2) send today's words, or (3) retry at the next touch. Recommend (1): option 2 brings back "the timer sends words Clara never reviewed", which is the thing being removed; the reconciler and the next touch catch up; the real fallback is the kill switch plus an alert when wake failures pass 5% in an hour.
Ten regression risks, ranked, each with what catches it: (1) double send from a timed-out turn: 4-minute limit, claim before compose, planted scenario; (2) tool side effects inside a retried turn: tools off in version 1, a test asserts zero tool calls; (3) one wake error killing the whole sequence after five retries: the step catches every wake error, scenario "wake throws five times" must never end failed; (4) nondeterminism against the 110 running timers: keep the swap inside the activity, replay 20 real production histories per workflow first; (5) the wake knowing less than today's prompt (price drop, other homes, call context): the context block carries those facts, shadow diff on real leads; (6) quiet hours: the hold stays in the workflow, the door re-checks; (7) consent and opt-out: unchanged gate order, scenario "STOP arrives during the wake"; (8) state drift: a silent wake must not move the touch index; (9) the reconcile sweep re-sending a touch the loop held: decide that a resume skips held touches; (10) a worker deploy mid-turn: the claim from risk 1, plus a chaos test.
Proof plan and PR chain, eleven PRs each one concern and none with a customer effect until the ninth: outreach permutation adapter with today's goldens; re-engagement adapter; 20 + 20 real production histories into the replay corpus; the 4-minute limit, replay-proven; the wake context builder, pure, tools off; shadow mode (wake after compose, log the diff, still send today's words, catch every error); the shadow diff report on this page; the company setting with its kill switch, dark; the activity uses the wake when the setting is on, Willows first; same for re-engagement; delete the setting and the old branch once proven. Test gaps found tonight: the permutation harness has nothing for outreach or re-engagement and no planted-bug controls; outreach has two recorded production runs to replay against, re-engagement zero.
Security note for Fede: while pulling the production numbers, the agent's first command echoed the production Temporal API key once into its own local log in this session's temp folder. It was redacted there tonight and appears in no saved file. Rotating that key is a third-party production write and is your call; recommend yes.
Full study with file and line citations: session scratchpad, temporal-study.md, with the raw production pulls beside it.
Do not build a reasoning layer for the hold-or-reply call. On the cards the rules cannot decide (typed by a staff member, nothing logged yet: 282 at Situs, 295 at Western Slope), the model was worse than the simplest rule at both companies. Situs: hold on every one is right 95% of the time; the model 81%. Western Slope: reply to every one is right 59%; the model 30%. A bigger model changed one answer in fifty. The reason is not the model, it is the card: 99% of these cards say only "typed by X at time Y". What does predict the outcome is who typed it and how: a lookup by company, source, typist and hours, learned from each company's own history, is right 95% at Situs and 66% at Western Slope, matching or beating the model at both. Keep the model for the one place it earned its keep: the rare card where the renter wrote something, to decide what Clara says, not whether.
| Who decides, on the undecided cards | Situs (n=282) | Western Slope (n=295) |
|---|---|---|
| Company default (Situs hold all, Western Slope reply all) | 95% right | 59% right |
| Lookup: company + source + typist + hours, no model | 95% | 66% |
| Sonnet 5.5, hold or reply | 81% | 30% |
| Sonnet 5.5, changed action allowed | 80% | 30% |
Note on the numbers: section 15 says 40% of Western Slope staff-typed cards are touched within 10 minutes; here only 27% get a person within 60 minutes, because this set excludes cards a person touched in the same minute they were typed. "Hours" in the lookup is a signal learned from history, never a gate on when Clara answers.
Grading was observable, not opinion: hold is right when a person texted, called, emailed, noted, booked or sent an application within 60 minutes; reply is right when nobody did within the hour and no person booked or sent within 24 hours. 1,516 model calls on the subscription, zero errors. The self-check plants a future event and asserts it never leaks into what the model sees.
Patterns, with confidence:
What this changes on this page: roadmap phase 4 shrinks. The judgment step is not a hold-or-reply decider; it decides what Clara says when a renter wrote something, and it stays behind the rules. Layer 1 gains three cheap rules: per-company typist lookup refreshed monthly, batch-typing per company, holidays. Model confidence scores mean nothing here (answers between 0.6 and 0.8 were right 29% of the time at Western Slope). Caveats: replies made outside AppFolio and the Zillow inbox are invisible; the Western Slope year is 2024 to 2025. Files: gate-harness/layer2_findings.md, layer2_results.json.
This is where the model earns its keep. Every automatic card that Clara would have owned got three synthetic follow-up wakes, at 24 hours, 3 days and 7 days: 1,252 wakes across 171 Situs and 249 Western Slope cards. A fixed timer with no check lands on top of a person already working the lead 44% of the time at Situs and 35% at Western Slope. Today's rules-only check still sends into fresh human activity 26% and 28%. "Wake and look" with the model cuts that to 11% at both, and to 4% and 7% when the model may change the action. On a lead where nothing ever happened, both the rules and the model send every time, 321 of 321: the model never invented a reason to hold.
| Who decides the follow-up | Sends into fresh human activity, Situs | Western Slope | Right call overall |
|---|---|---|---|
| Fixed timer, no check | 44% (197 of 443) | 35% (240 of 686) | – |
| Today's rules (stop / wait / send) | 26% (115) | 28% (190) | 70% |
| Wake and look, Sonnet 5.5, proceed / hold / stop | 11% (50) | 11% (75) | 85% |
| Wake and look, changed action allowed | 4% (17) | 7% (48) | 91% (generous: a changed action is never marked wrong) |
The biggest gain is at the 24-hour wake: 62% right for the rules against 91% for the model. Opus 5.5 on the 40 hardest wakes changed 11 answers and did not change the picture; Sonnet is enough. 2,504 calls on the subscription, zero failures. No real Clara sends are in this data (Clara never ran at Situs, and the Western Slope year predates her), so every "send" here is hypothetical.
Four rules to add today, no model needed. Most of the rules' misses are one shape: a single teammate text with no renter reply yet. The rules send anyway, on purpose, because a lone greeting never holds a follow-up. In 188 such wakes, the model held every one where that text was under 12 hours old (74 of 74). A time box catches most of these. Three more: the renter wrote back to a teammate (37 wakes, model holds 91%); a showing is booked for later (36 wakes, model never proceeds); an application is out (22 wakes).
What a changed action looks like. Allowed to do something other than the generic check-in, the model turned 175 wakes into something better: 88 showing messages (confirm, after-tour, reschedule), 43 answers to a renter's unanswered message, 39 application nudges. It never did this on a lead with nothing going on.
Recommendation from the prototype: ship the four rules now inside today's check; then make the wake a model look that may change the action, for leads where anything human happened since the last touch. Files: gate-harness/followup_findings.md, followup_results.json, followup_calls.jsonl.
In one breath: Situs needs one setting for Saturday. The reasoning layer is not worth building for "should Clara reply"; cheap rules beat it. It is worth building for follow-ups, where today's fixed timers land on a person a third to a half of the time and "wake and look" cuts that to one in ten. The alarm-clock seam already exists and the Temporal change is small and well-contained. The glass is empty at both customers until notes, activity and assignee flow fresh at every wake. Nothing shipped tonight; no PR was opened.
| Pattern | Confidence | Evidence | What it changes |
|---|---|---|---|
| One company setting (the source list) gets Situs to Saturday | High | 96 of 96 Zillow Rental Network cards system-created; four real cards walked (16.2) | Phase 0 = one PR of ~250 lines plus four ops steps |
| Fixed follow-up timers land on a person a third to half of the time | Medium. The year had no Clara in it, so no cadence ever stopped on a reply. In production, 65% of finished follow-up runs ended because the renter replied first and only 4.5% reached a second touch; but 58% of the 98 runs live right now are already past touch 1, so the quiet-lead group is growing since the early-October fixes | 1,252 wakes; 44% Situs, 35% Western Slope (16.5) | Phase 3 is the biggest customer-visible win |
| Four plain rules fix most follow-up misses without a model | High | 188 lone-greeting wakes, 74 of 74 under 12 h held (16.5) | Ship inside today's check, before any wake work |
| A model at intake is worse than the company default on hold-or-reply | High | 81% vs 95% Situs, 30% vs 59% Western Slope; typist lookup 66% (16.4) | No reasoning layer for intake; three cheap rules instead |
| A model at follow-up time is right 85%, and proposes better actions | High on the 85%; the 175 changed actions were listed, not scored | 175 wakes turned into showing, answer or application messages (16.5) | Phase 3's wake may change the action, behind the rules |
| The alarm-clock seam exists; the Temporal change is one call inside one activity | High | scheduled-wake merged Oct 14; 654 runs, 0 failed, 110 live (16.1, 16.3) | Phase 3 is 11 small PRs, 8 with no customer effect |
| The picture is empty at Western Slope and Situs | High (verified in code) | Notes import off everywhere; no assignee in the picture (16.1, 16.2) | Phase 1 before any decision can see Kat's call |
| The follow-up check is blind to AppFolio staff texts at Situs | Medium | Message sync listed as in progress; median staff text at 19 h (16.2) | Connect the message sync before Saturday or accept week one |
Decisions for Fede this morning, one line each, recommendation first:
Phase 0 shipped: per-company list of lead sources Clara answers. Merged (PR #20019) and proven live at Willows on Oct 15: with the list set to Zillow Rental Network only, a Zillow card got Clara's reply and assignment (card 232), a staff-typed TurboTenant card was left alone (card 233), the list was then restored. Evidence: proof comment. Situs can be set on Saturday with one command; new companies start with an empty list (Clara answers nothing until a list is set).
Phase 1 shipping (Oct 16): the glass is filling. Three merged, no switch, live everywhere: the card sync now keeps every dated note and the latest activity as neutral fields on the mirrored card (PR #20255, proven at Willows card 128: three dated notes, newest activity a note on Sep 22; zero extra AppFolio requests); the person picture reads the assignee, source label, last activity and notes through that contract (PR #20288, 30-day replay of pictures with identical first-touch and follow-up decisions); and every follow-up wake now looks at what happened since Clara's last touch, classifies it and logs it, with the send unchanged (PR #20275, the §16.10 minimum slice, log-only). Then two more, also merged and live: the first-touch decision log records the card as staff see it (assignee kind, source label, status, note and activity counts, last-activity age, notes present; PR #20311, 913 real decisions byte-identical; the replay first looked like a gap at Western Slope, 241 of 1,010 people with recent cards reaching the decision step; a read-only check showed the replay counted by last-seen date, which the hourly sync refreshes on every card, so the 1,010 are the whole back catalogue; of the cards that actually arrived in the live window only 4 at Western Slope and 2 at Situs have no inquiry record, nearly all co-signer or not-yet-live cards by design, with one pending Oct 15 Western Slope card still unexplained; the replay now needs the card creation date, not last-seen), and the arrival race is closed: one shared timeline import per new lead, and the decision log waits up to 6 seconds for it before reading the picture, recording done / skipped / failed (PR #20322; at Willows the itemized entries visible at decision time went from 0 to 21 of 36; the import stays behind the existing staff-context setting, on only at Willows). Proven in production at 07:55Z Oct 16: a real new lead at Willows produced one first-touch decision line carrying every new field (import done before the decision, assignee none, source label, card status active, 0 notes, 1 activity "card created" 0 days old, no notes text), decision unchanged (reply, log-only). Evidence comments are on PRs #20288, #20311 and #20322. The wake-look line landed at 13:00Z Oct 16 on the morning's first re-engagement wake, at the Fairhaven sandbox company (first written up as Western Slope; the org id is the sandbox's): since the last touch five days earlier, a second card for the same person and nothing else (no coworker message or action, no renter reply in the PMS or to Clara, no staff activity); the gate decided "send" on the old rules, log-only (evidence on PR #20275). At the 14:00Z follow-up run the worker wrote 19 wake-look lines, 14 at Willows and 5 on real customer leads (17 nothing changed, 1 second card for the same person, 1 renter replied to Clara), all log-only with the gate deciding as before. Phase 1 is fully proven in production.
Two notes for the builders: the source-list setting must show on the company page, which is Gera's settings lane, so a heads-up goes to Smith on the bridge before that PR. And section 9 line 5 is sharpened by 16.4: the Western Slope default is no longer "reply to every staff-typed card" but "reply unless the typist's own history says hold".
In one breath: 25 of 150 real follow-up texts and emails in the last 30 days (17%) went out while a warning sign was already in the thread; 21 should have been held or said something different. Western Slope 23 of 105, Camellia 2 of 45. Four more were wrong for reasons outside the seven signs. All 39 cases (25 bad, 10 clean, 4 other) are now harness cases for the wake loop: first what happened, then what Clara should have done.
| Warning sign at send time | Sends | Example | What a wake-and-look does instead |
|---|---|---|---|
| Staff already handled the person outside PropFlow (AppFolio texts, a call, a tour they booked) | 8 | Greg W.: "we had already stopped by the property with her last Friday" | Hold |
| Clara's own promise or question to staff still open | 6 | Jennifer C.: voucher question with the team; Clara asked for a tour instead | Follow up on the promise, not a tour |
| Tour booked, done or cancelled, and the text ignored it | 9 | Thomas R.: toured, waiting on the application link, got a self-guided tour offer | Do the next step (link, after-tour, other homes) |
| Second record for one person started a second timer | 5 | Tessa A.: a text and an email 26 minutes apart, while she was already applying | One person, one alarm |
| Person declined this home earlier in the thread | 4 | Caleb Q.: "We talked about this at length yesterday… Are you an AI assistant?" | Hold, or offer what they asked for |
| Not a renter (vendor, listing solicitation) | 3 | a photographer selling services got two "want to tour?" texts | Hold |
Three patterns. Kat handles people by AppFolio text and by phone, and the timer never reads either before sending. Clara's promises on calls ("the team will reach out when a 2-bed opens") are never closed, and the generic "what days work?" runs straight over them. Duplicate records start duplicate timers. The count is an undercount: AppFolio notes, staff calls and staff-booked tours are invisible to PropFlow today, so three of the eight staff-touch cases surfaced only because the renter said so.
The Caleb bug, separate from the rules (high confidence, reproduced on main and in the logs). A reply stops only the timers on a person's active cards. A cancelled-tour card counts as not active, so his three days of "not interested" replies never reached the timer running on Kat's card, while another rule deliberately keeps that timer alive because the lead is "back in play". The log said "no live cadence to stop" eight times. Nothing ever moves a card to not-interested on those words either; the pre-send check reacts only to "stop texting" and "unsubscribe". Eight Western Slope timers in 30 days sat on cards a reply cannot reach. Done today on Fede's yes: his timer terminated and his record marked closed, which the 1 AM repair job would otherwise have revived. Proposed fix, as a bug with no switch: a reply stops every running timer the person has, whatever the card's stage or property. The "one clock per person" PRs from Oct 9 and 11 merge timers across homes but do not cover this.
Scored (Oct 15, 1 PM; Sonnet 5.5 judge on the subscription, 103 calls, nothing sent). On the same 39 real cases, "wake and look" avoided every bad send that needed a hold or a different message; the rules see too little to do it.
| Scorer | Bad sends avoided (of 25) | Clean sends kept (of 10) | Hold precision | Hold recall |
|---|---|---|---|---|
| What actually happened | 0 | 10 | n/a | 0% |
| Today's rules (as modelled) | 5 | 10 | 80% | 16% |
| Today's rules + the four plain rules | 7 | 10 | 86% | 24% |
| Rules + four + three picture fields (staff call, open promise, "doesn't fit") | 19 | 10 | 95% | 76% |
| Wake and look, model over the timeline | 22 | 9 | 93% | 100% |
The three bad sends the model let through were Brody's, where only the home name was stale, so sending was right. Its one wrong hold was Colby, where a next-day text was fine. Its proposed actions matched the expected note 27 of 39 times, partly 11, disagreed once; the "partly" is mostly waiting on the team where a quick check-in with the person was better. Stable on a repeat pass: 24 of 25 the same. The rules' gap is information they never see: a staff phone call, a question Clara passed to the team, a person saying the home does not fit. Caveats: the modelled copy of today's rules holds five cases production sent (Ethan, Tessa twice, Thomas, Colby), worth a check against the real code; five sent texts are cut at 300 characters by the recording, and the first prompt version tripped on that. Confidence: high on the direction, medium on the exact numbers (39 cases, one customer dominates).
Harness file: 39 labelled cases (first name and last initial only, no phone or email) in the session scratchpad, gate-harness/real_cases.jsonl, shape: timeline up to the send, the picture at send time, the text sent, the reply, expected action (hold / proceed / do different). Next: run last night's follow-up harness over these real cases and report hold/proceed accuracy per rule and with the model.
Fede asked what the must-haves are for a successful Situs launch. Everything below was read in production on Oct 16 at about 03:30Z; nothing was changed.
| Item | Found | Ready |
|---|---|---|
| Clara's AppFolio user (her seat) | Set nowhere: not on the company connection, not on any of the 52 buildings. Once live, every new card stalls at the assign step. | No |
| Lead-source list | Not set. For an existing company that means every source; the Saturday command must run before the live flip. | Needs the command |
| Live switches | Company not live, all four modules off, 18 of 52 buildings have their own building switch off since Oct 6. | Gera's checklist |
| Leasing mailbox (Google) | Connected, login refreshes, read and send granted, never read a message: the reader skips companies that are not live. | Unknown until live |
| AppFolio messages in the picture | Off at Situs; the inbox backfill runs only for JP&Co. Zero Situs messages mirrored. | No |
| Lead sync health | Guest-card job completed 52 of 52 on its last passes; the financials report job still rate-limits on about 13 buildings. | Watch |
| Knowledge | 20 of 52 buildings have any entry; deposits on 14, fees on 9, pets on 8, parking on none. | Thin |
| Tour calendar and agents | No calendar on the company, people or buildings; no leasing agents in the system. | No |
Also seen: emergency on-call is two PropFlow stand-ins (set Oct 14); since Oct 9, 63 new Situs leads were declined at the assign step (48 not live, 15 no email). Recommendation if Saturday goes ahead: set the list, set Clara's seat, keep it first-email only, and have the AppFolio message backfill on at Situs before any follow-up runs there.
Fede's framing: the minimum slice that makes Clara a coworker is to wake, look at what happened since her last touch, then act, and he expects 80 to 90% of wakes to be a plain send. We tested that on a year of AppFolio activity logs with synthetic wakes at 24 hours, 3 days and 7 days (Situs Zillow Rental Network and all Western Slope leads), the last 30 days of mirrored cards, and Clara's real wakes of the last 30 days at Western Slope and Camellia. Willows (test) is excluded from the headlines.
Of 3,342 wakes on real customer leads:
Classes overlap; only "nothing changed" stands alone. "Mostly just send it" holds only on what PropFlow sees today: nothing changed on 69% of Western Slope real wakes and 98% of Camellia's. On the full AppFolio log it is 46%, because a coworker was in on 32% of wakes.
Production code matches the harness (Oct 16, after PR #20275 merged): the shipped classifier, replayed read-only over the same 30-day corpus, put all 1,047 wakes (830 real, 217 synthetic on mirrored cards) in the same classes as the harness, and finds Clara's last touch on its own on 827 of 830 real wakes with no class moving. Matching it exposed two harness bugs, now fixed locally: card notes were only read for people with a message thread (no class changed), and a second inquiry on the same card was counted as a duplicate; with that fix the real-wake mix is 9% duplicate card (was 18%) and 86% nothing changed (was 77%). The 2,913 wakes from the year-long AppFolio logs have no person picture, so the production code cannot replay them. The Willows log line is the only real test and lands here with the first morning follow-up.
What today's rules did. They send on about 99 to 100% of wakes in every class, because they cannot see staff activity in AppFolio.
| Class | Wakes | Today's rules send | Candidate hold or stop |
|---|---|---|---|
| Coworker already wrote or called | 738 | 100% | 88% |
| Coworker acted outside messages | 226 | 100% | 95% |
| Renter replied in AppFolio | 344 | 100% | 57% |
| Lead moved on | 838 | 99% | 89% |
| Duplicate card | 480 | 99% | 46% |
| Nothing changed | 1,642 | 100% | 0% |
Of 151 real follow-ups sent at Western Slope and Camellia in 30 days, 8 went out after a coworker had already written or called, and 0 went out while the renter was still waiting for an answer.
The coworker-candidate split. The candidate look decides send as-is, send adjusted, hold or stop.
| Group | Wakes | As-is | Adjusted | Hold | Stop |
|---|---|---|---|---|---|
| Situs year (synthetic) | 285 | 38% | 12% | 34% | 16% |
| Western Slope year (synthetic) | 2,628 | 36% | 22% | 21% | 21% |
| Western Slope real, 30 days | 152 | 64% | 32% | 4% | 0% |
| Camellia real, 30 days | 60 | 88% | 8% | 2% | 2% |
Precision caveat: a coworker acted in the next 24 hours after 11% of holds and after 14% of quiet send-as-is wakes, so the next day does not separate them. A hold rests on a fact on the card, not on predicting staff.
Several staff on one card. Situs: 905 cards in the year log, with 0, 1, 2 and 3 or more staff on 4%, 35%, 33% and 28%. On 295 (33%) a shared office login and a named agent both acted, and the agent was first on 184. Western Slope: 63 of 876 cards (7%) had both, the agent first on all 63. PropFlow's own copy shows at most 2 staff per card.
Three walked examples (Western Slope, real wakes):
The minimum slice that cannot break anything:
Everything else stays log-only.
Checks and caveats:
Playground: ~/.claude/skills/knowledge-coverage/harness/wake-playground/ (README has the commands; five scenarios, one mutation control). Local only, no PR, no CI.
Fede asked: if we run Zillow leads at Situs in Supervised mode, is it safe? Supervised holds every prospect email and text for review. It does not hold the write that assigns the guest card to Clara in AppFolio. At Situs today that write is stopped only by two other things: the per-building "Guest card after a call" switch is off on all 53 buildings, and no Clara AppFolio user is set. Turn either on and cards get assigned with no approval. Read-only inspection of main and production, Oct 16.
| Write path | Guard | Held in Supervised? | Stopped at Situs today by |
|---|---|---|---|
| AppFolio: assign card to Clara | Company live, lead-source list, building switch, Clara user | No | Building switch off; no Clara user |
| AppFolio: notes, "email sent" entry | Building switch; only after a send | n/a (nothing sends) | Building switch off |
| AppFolio: create card, showing, send application | Building switch; showing-sync setting; application-link mode | No | All off or default |
| Prospect email (first, follow-up, tour) | Live, module, Supervised | Yes | Held as drafts |
| Prospect text | Supervised; Twilio backstop | Yes | Held as drafts |
| Staff email: tour booked or cancelled | None | No | Only fires on a tour booked by call or text, not by the card |
| Voice callback to a prospect | Callback setting only | No | Setting off |
| Slack review card | Channel set on the front door | Intended | No channel yet |
| Situs settings today | Value |
|---|---|
| Company live | Off |
| Modules | All four off; Leasing in setup |
| Lead-source list | Not set (every source) |
| Guest card after a call | Off on all 53 buildings |
| Clara AppFolio user | Not set |
| Review Slack channel | Not set |
| Card sync | Running (pause is gone); read-only toward AppFolio as far as this repo shows |
Minimal plan (turning on is Fede's call):
Two PRs: (a) the assign step skips when the company is Supervised, so Supervised means no AppFolio writes. This is a fix, no switch, in progress. (b) A watch-only review card with no @mentions and no reminder bumps while in shadow. This is a new capability: it needs a setting and Fede's go. Declined by Fede (Oct 16, 16:10Z): "watch mode no, do not build new things." Supervised stays as designed; only the assign leak is fixed.
Sandbox proof: at the Fairhaven sandbox company with the same settings, create one Zillow card and one TurboTenant card. Expect a held draft and a Slack card for the Zillow card only, the assign skipped (after PR a, as a Supervised skip), the AppFolio card unassigned with no note, and no email or text delivered.
What the shadow will not show: follow-up drafts (the follow-up never starts because the first email is held, not sent), and the 18 buildings whose own Leasing switch is off (refused with no Slack card). Held drafts do not expire on their own (inference); approving one later sends it.
Oct 20 readiness: company live switch off; leasing module on; leasing.prospects not yet in drafts mode; no Slack review channel wired (held drafts would show only on the review page); 15 Zillow Rental Network cards since Oct 6, one a day, all with email, none assigned; Clara has no AppFolio user at Situs yet; leasing inbox reading paused pending the Google security audit. Turn-on order on Fede's yes: wire the #situs-group review channel, set leasing to drafts, flip live.
Assign consumer: clara-guest-card-assign-consumer.ts:162, :349, :355. Building switch: guest-card-note-intent.ts:181-201. Drain: guest-card-outbox-drain.ts:2321-2340, :3040-3093. Supervised: leasing-supervised.ts:31; clara-guest-card-first-email-send.ts:759; leasing-prospect-text-review.ts:85. Entitlement: resolve-module-entitlement.ts:289-293. Staff tour email: send-pm-tour-confirmation.ts:641-659. Voice callback: escalation-callback-call.ts:189. Lead scope: lead-scope.ts:27.
Today the claim fires on detection, in parallel with the reply, and never learns the reply's verdict. At Western Slope in 30 days, 43 of 71 claims came on detection; 28 came after the email. One detection claim never got a reply. On Oct 14 the card for Lauren A. (2913) was overwritten from a human to Clara.
Ruling (Fede, Oct 16): Clara claims the card only after her message went out (sent, or approved and released). A held draft means no claim. Shipped and proven (Oct 16): #20476 deleted the claim-on-arrival step; the only claim now runs inside the delivered-first-email write-back, live everywhere since 18:24Z. Western Slope 30-day replay: 70 of 72 claims unchanged, the two dropped were a held email never sent and a card claimed by an older path with no Clara email. Willows live run, card 247: email sent 18:26:29.05Z, claim queued 18:26:29.36Z, AppFolio shows Clara as assignee at 18:26:33Z, old step logged nothing. Not run live: the held case (needs Willows in Supervised). Follow-ups in #20478. Never over a human (Oct 16, #20489, merged and live 20:41Z): if a staff member already holds the card, Clara sends her email, logs the skip and leaves the card alone; the "Email Sent" note still lands. Western Slope 30-day replay: 72 claims, 1 would now be skipped (card 2913, the case Fede flagged), Situs 0. Willows live run, card 249: staff user assigned 2 s after creation, email sent 20:55:40.0Z, skip logged 20:55:40.3Z, no claim row, AppFolio still shows the staff user at 20:56:43Z. Unknown-holder and lookup-failure cases are unit-covered only. Staff-answer leak (same day): a reply Clara writes after a staff member answers her team note was labelled as the staff member's words at the send door, so Supervised never held it. Fixed as three small PRs: #20477 texts go through the same hold as every Clara reply (merged), #20479 the door label says it is Clara speaking (merged), #20484 the email leg (armed). Western Slope 30-day replay: 6 relayed answers, all unchanged because its leasing is Live. Staff notices are never held (Fede). Handing the card to the human on handoff, and back to Clara afterward, stay options for a later yes.
| State | Next action is | Assignee shows | Problem |
|---|---|---|---|
| New card | Clara | Clara in seconds (hours if the robot lags) | Often before the reply |
| Clara or prospect replied | Clara | Clara | None |
| Staff texts or calls in AppFolio | Staff or Clara | Clara | Nothing reads the assignee |
| Staff takes the card | Staff | Staff, then back to Clara on the next inquiry | "Stay out" is not enforced (Lauren A.) |
| Escalation or handoff | Human | Clara, plus one generic note | The human is never assigned |
| Tour booked or done | Clara or host | Clara | Host not shown |
| Application submitted | Staff | Clara | Stale |
| Human finishes their step | Clara | No mechanism | Nothing assigns back to Clara |
| Gate | Reply | Claim |
|---|---|---|
| Company live, phone-only, staff's own card, duplicate, backfill, lead-source list, already applied | Yes | Yes |
| Our own card read back early, or our own home-add | Yes | No |
| Already in touch, or already answered | Yes | No |
| Leasing Supervised | Yes, holds the email | No |
| Leasing off, opt-out, contact limit, test recipient | Yes, refused at send | No |
| Draft guard, fact-trace hold, defective draft | Yes, held | No |
| Card already held by a human | No | No |
| Former tenant | No | No |
The send-time refusals exist only at send, so the claim cannot know "should I reply" unless it runs after the send. That is why claiming after the message went out beats copying every gate.
| Vendor | Owner shown | Handoff to human | Back to AI |
|---|---|---|---|
| AppFolio Realm-X | Not documented | Team-set trigger, e.g. tour confirmed | Not found |
| EliseAI | Not found | "Human handoff escalation" | Not found |
| Funnel | One guest card; CRM tasks at handoff | Task in the CRM | Not found |
| Knock (RealPage) | AI inside the CRM, all activity logged | Staff tag in and out | Implied by tag-out |
| Yardi Chat IQ | Not found | Live connect to a specialist | Not found |
| Entrata ELI+ | Lead score, not an owner | Implied | Not found |
| BetterBot | Exclusive, releasable claim; AI pausable per person | Agent claims the conversation | Implied by release |
| Zuma | Agent profile; "respects guest card ownership" | Notes or tasks to staff | Not found |
Almost all of this is vendor marketing; no vendor documents an "AI owns this lead" field or handing a lead back to the AI. Closest match is BetterBot. Sources: appfolio.com/blog/product-update-2026-q2, realpage.com/apartment-marketing/crm/ai-leasing-agent, funnelleasing.com, betterbot.com/features/crm, getzuma.com/leasing-ai, entrata.com/platforms/eli, yardi.com/blog/?p=36927.
Still unverified: whether AppFolio emails the assignee or the prospect on an assign. One look at the Willows test card (232) would answer it.
Two consumers on the same row: clara-guest-card-assign-consumer.ts:113-117, claim at :349/:355/:385. First email: clara-guest-card-first-email-consumer.ts:1641-1868; send gates send.ts:759, :1138-1163. After-send claim: guest-card-write-back-outbox.ts:138-160. Unused human-holds-it check: reply-eligibility.ts:198-227 (no callers). Handoff note: open-matter.ts:1259-1275; deferred reassign: drain.ts:2297. Assign design: guest-card-note-intent.ts:35-60. Manual handoff script: #10538. Earlier Supervised-skip PR: #20475 (superseded).
Three bugs came out of the Caleb case. Each is a fix, so each ships live with no switch.
| Bug | Before | After | Proof |
|---|---|---|---|
| A reply only stopped the active card's timer | Caleb texted "not interested" but his cancelled-tour card kept a follow-up timer running, so he got more texts. | One reply stops every follow-up timer the person has, whatever the card's stage (PR #20114). | Willows, Oct 15: a test person with two timers (one on a cancelled-tour row) texted "not interested"; both stopped within 4 seconds (evidence). 30-day replay: 12 Western Slope cards had a timer a reply could not reach; now all reached. |
| A call created a second card for a person staff had just typed in | Staff typed card 2992 at 2:56 PM; his 3:18 PM call made card 2993 for the same phone. | Before creating a card from a call, Clara looks the caller up in our mirror of AppFolio cards and adds the call to the existing card (PR #20113). | Repro over his real records, red on the old code, green on the fix; Willows live run Oct 16: one card and the call note on it, but the sync had already linked the lead to the card, so the new lookup did not fire; the mirror-only path stays covered by the repro only, and the real-world shape is covered by the Oct 14 cross-home rule. |
| A second guest card for someone who already inquired paged a false missed-lead alarm | The second card failed the lookup on every retry and paged. | It folds quietly into the existing lead (PR #20090). | Willows, Oct 15: card 231 folded into the lead on card 224, no alert (evidence). |
Also shipped the same day under Fede's "PMS code lives in adapters" rule: the guest-card drain and mirror lookup no longer name AppFolio (PR #20160), the mirror row is now a written neutral contract (PR #20174), and the "did a staff member touch this person since Clara's last message" check is one shared reader that renewals and maintenance call as is (PR #20161). Overnight (Oct 16) two more landed: the two Clara guest-card consumers read the neutral mirror contract instead of AppFolio fields (PR #20191), and the person picture accepts neutral conversation rows from any PMS as one more source, which is how renewals will feed AppFolio texts into the same staff-touched check (PR #20198). Then the "first email about this home already sent?" check (PR #20236, replay of 1,355 inquiries byte-identical). Then the guest-card property tags (PR #20278, 794 real decisions byte-identical). Each proven by a replay over the last 30 days of real records with zero differences. Then the lead emit from the mirrored card (PR #20296, 3,472 real lead events at five companies byte-identical). Then the inbound-message builder (PR #20308, 3,473 decisions byte-identical). Then the engine turn's inquiry ids (PR #20326, 1,374 rows byte-identical). Then the household engine's grouping evidence (PR #20332, 10,258 rows byte-identical). Then the tour's card pointer (PR #20337, every real tour and card lookup byte-identical). And the prospects list (PR #20342, 13,184 rows byte-identical, four new contract fields). All eight mirror readers now read the neutral contract; second-link debt (the inquiry record's own PMS block and its writers, page row names in Gera's lane, comments) is listed in the PR bodies and continues one per PR (the listing-lead gate in the leasing tools was already deleted by #14408, so it leaves the list). First second-link PR merged: the household resolver reads the application group and co-signer flag through a written reader instead of the record's PMS block (PR #20357, 11,678 rows at five companies byte-identical). Merged: the prospect summary's shared "no source recorded" check (PR #20362, 2,583 applications identical). Merged: the prospects store reading only contract fields (PR #20367, 13,184 rows identical). Merged: the household engine's remaining block reads in the model, reminder anchor, sync bridge and writers all go through the same reader (PR #20389, 11,708 rows and 58,703 outputs at five companies byte-identical), and, now merged, the prospect summary takes the renter's own words from a named reader instead of the legacy import (PR #20388, 1,446 prospects byte-identical). Also merged: the prospects list's "is this card linked to a real person yet" check and placeholder id live in one PMS-layer reader, and the row builders accept contract rows (PR #20400, 2,644 cards and 10,336 outputs at five companies byte-identical). Also merged: the conversation card and both prospect detail pages read the inquiry panel entry through one PMS-layer reader (PR #20406, 1,466 prospects at five companies byte-identical). Also merged: every production caller of the prospects row builders (list, search, tour lookup, detail page) now reads cards through the PMS layer and the stored-row builders are deleted (PR #20412, 13,221 outputs at five companies byte-identical). Also merged: the prospects list asks the PMS layer which system owns a company's mirrored cards and what type a batch carries, so the loader names no vendor (PR #20421, 2,827 decisions at seven companies byte-identical). Also merged: the legacy inquiry-matching module itself moved into the PMS layer with a repo-wide check that nothing outside it imports the module (PR #20426, 1,580 prospects at five companies byte-identical). Also merged: the record-owner setting's list of PMS choices, their labels and the "is this a PMS" check live in one PMS-layer file, so the prospects module names no vendor (PR #20430, 169 answers at seven companies byte-identical). Also merged: the prospect detail page's link to the application in the PMS comes from a PMS-layer resolver and the loader names no vendor (PR #20431, 369 links at five companies byte-identical). Also merged: the conversation card's "application already sent through the PMS" check takes a neutral input, so the loader names no PMS block (PR #20433, 28 real sends at five companies identical). Also merged, the last code link: that check's contract and resolver live in the PMS layer with a repo-wide rule on who may import them (PR #20437, 28 real sends identical). Left after that: the household plan field names (the link kinds merged as PR #20438, option A below), and the record's PMS block key itself (waiting on the bridge answer about the page row names).
Household link kinds (internal, done under the standing grant, no decision needed): the household engine saves a link kind on every application-group row as the literal strings appfolio_application_group and system:appfolio_application_group, at all five companies. Three ways to get the vendor word out of core code: (A) keep the saved strings as they are (they are already provider-prefixed, which is what the rule asks for), move the two constants into the PMS layer as the provider's application-group kind, and have the household code compare against that registry value, so no row changes and no migration; (B) backfill every row to a neutral kind plus a provider column, one migration per company, proven by a before/after count; (C) leave it. Taking A (no customer effect, so it proceeds on the lane's own call): PR #20438, merged Oct 16, no behavior change, no data touched, 1,643 real memberships at five companies written byte-identical; B only if a second PMS ever needs a different kind string.
Prospect list fixes (Oct 16, from Fede's screenshot of the Western Slope pipeline; improvements to live behavior, no switch): #20444 a card with a blank source shows our record's source (4 Western Slope rows gain a source); #20445 a row folded from two cards keeps every card id, so our records attach (Natalie H. is one row again); #20446 company staff never appear as prospects, one shared definition of staff with the follow-up gate (removes Jay T. and Kat B., nobody elsewhere). All three were live by 15:37Z Oct 16 and proven with the real list code at the production commit over live Western Slope data: 205 rows became 201, Jay T. gone, Natalie H. one row (Tour Confirmed, Clara), Amanda D. Apartments.com, Thomas R. Phone, two more rows gained Zillow, "No source recorded" rows 8 to 4 (the four have no stored source anywhere). Suspicion left open, not fixed: our record 8964dc76 (Marleen J., referral, not interested) was minted Sep 7 from card 2872/2898 whose only name is Leeila G.; the card is flagged name-incompatible, so the person link at sync time may be wrong. After #20445 that record sits under Leeila's row; the fix, if it is one, belongs in the sync-time person link, not the list.
Next wake-on-change case (Oct 16, from the Western Slope prospect list): Kristin B.'s Uloop card was created in February; on Oct 7 AppFolio recorded renewed interest on it and on Oct 13 staff texted her from AppFolio. Clara never woke: today a wake fires only on a new card or a new inquiry, never on a change to an old card. This is the first real case for "the alarm reads the picture" to also fire on a card change (status, activity, note). No fix yet; it is the next link after the glass is full.
One decision for Fede from this chain (yes / hold): the inbound-message reader takes the renter's own words and listing source from a snapshot stored on our inquiry record when the card was first created, not from the mirrored card, which later syncs keep fresh. Measured on the last 30 days: 230 records with both, 161 identical, 69 differ, and for 26 of them (13 renter texts and 11 sources at Western Slope, 1 and 3 at Situs, 1 at JP&Co) the reader would return different words or a different source. Switching the reader to the mirrored card is therefore a behavior change toward newer data, not a cleanup. Recommendation: yes, switch, proven by a replay that lists the 26 changed records and a Willows run; until then the snapshot read stays and the chain leaves it alone.