Renewals, end to end: levels of autonomy

Who decides the terms, who talks to the tenant, who sends the paperwork, and how a customer steps from "we review everything" to "Clara runs it".

2026-10-12 · Proposed, pending Fede's review · sources and pending inputs in §12 · internal

1. This week 2. The levels 3. How it fits 4. Roadmap, minimum slices 5. Today, and the tangle 6. What the tenant and office hear 7. Notice to vacate 8. Settings 9. Camellia and the market 10. Testing 11. Decisions Fairhaven proof Month cards prototype 12. Reference

Four layers, and today three of them hang off one switch. Who decides the terms. Who talks to the tenant: always Clara. Who sends the paperwork. And the rollout gate, Off → Supervised → Live, whose only job should be whether a real tenant sees Clara's words before we have watched her for a week.

flowchart LR
  P["Lease 90 days out"] --> D{"1 · who decides\nthe terms?"}
  D -- "Clara, by policy" --> C
  D -- "the team reviews\nthe monthly list" --> C
  C["2 · Clara talks\noffer · reminders · replies"] --> A{"tenant says"}
  A -- yes --> W{"3 · who sends\nthe paperwork?"}
  W -- Clara --> AF["AppFolio offer,\nsigned in the portal"]
  W -- office --> OF["'send the paperwork'\nemail to the office"]
  A -- no --> N["notice-to-vacate\nguidance, nudges"]
  A -- counter --> E["escalation\nto the office"]
  G["4 · rollout gate: Off · Supervised · Live\nholds Clara's words for a week, nothing else"] -.-> C
  style G fill:#fff3cd,stroke:#b45309,color:#333
WhenWhatWhose press
Wed 10/14, client meetingWestern Slope to Supervised: their team reviews the list, the office sends paperwork, we approve every messagefour settings: Fede
Week 1Every message approved by us; 24 to 48 hour battle test on Fairhavenus
Week 2Live: their team approves the list, Clara sends, nobody from PropFlow in the loopFede
Later, per customerClara sends the paperwork → the list becomes optional → meeting notes feed the decisionsFede, per customer

Six decisions in §11.

The full design

1. This week: the basic version, live at Western Slope

This replaces the step order on the Western Slope page from 10/8: paperwork is no longer tied to Live (Fede, 10/12). The deliverable for Wednesday's meeting is the most basic version, live. Their team gets the monthly list and answers by email reply or on the page. Clara sends the offers and handles the replies. The office sends the paperwork. For the first week Fede and Gera approve every message before a tenant sees it. Week 2 goes Live with nobody from PropFlow in the loop.

Western Slope today, read from production on 10/12

SettingTodayFor the flipWhy it matters
Renewals moduleOffSupervisedthe flip opens the first list that minute (Lincoln and Courtyard leases are on it; 18 leases, 12 would send, 6 held, per the 10/12 dry run)
Who sends the paperworknot setthe officethe 10/8 write set the rent rule, eligibility and the 90-day start but deliberately left this unset (ledger). Unset means Clara in code today: the robot would create AppFolio offers on day 0, before the list is approved, and AppFolio emails the tenant (per code comments). Fede 10/12: unset must mean the office, the lower level; fix below
Renewal reviewersnoneKat, Jaywith no reviewers the monthly list goes to nobody
Rent ruleflat since 10/12 evening (was market rate) · 12-month only · month-to-month +$150donetheir team changes any rent on the list anyway
Renewal calloffoffas agreed on the 10/7 call
Per-building "autonomous renewal" flag0 of 90 buildingsdelete it (fix); until then, on for every building on the lista Camellia-era leftover Fede never asked for (10/12); the daily check skips any building with it off, so the org-level mode alone starts nothing. Buildings that never get renewals (affordable housing) are a different thing: the per-building module Off row, already used for Lincoln and Courtyard
Company go-live stampliveliveemails can go; the two global arms are on

Before the flip

Items 2, 3 and 5 are fixes to live behavior and proceed under the standing grant. Item 1 is off the table (D1 = b). Item 4 waits for D3. Three more fixes from Fede's 10/12 rulings, no switch: (7) an unset paperwork sender means the office, never Clara ("it wouldn't make sense to default to a higher autonomous level and accidentally send it out"); Camellia's and Willows' rows were pinned to Clara on 10/12 22:40Z so nothing changes there (ledgered); the code default flips in PR #19100 (merged 10/13 00:30Z; the AppFolio robot then runs only on an explicit "Clara"); (8) the per-building autonomous flag is deleted (PR #19080, merged 10/12 23:20Z; Willows' renewals row set Off the same night so the test property does not start 85 held renewals; leftover writes to the dead field: issue #19083, stale runbook wording: #19088); (9) the renewal reviewers move into the customer's own settings page, not a staff-only screen (not started; UI gets a preview before merge). "Offer" on this page means Clara's first text with the terms, never the paperwork.

  1. Hold everything in week 1 (D1: Fede chose (b) on 10/12, so this is not built). Today, once the list is approved, the offer texts go straight out; only Clara's free-form replies are held. Add a "check before send" stage on the list page for the Supervised week: the exact texts and recipients, one approve (D1).
  2. A held reply never dies silently. Today it expires after 24 hours and the tenant hears nothing. Re-ping until decided (D4). Since this afternoon Clara texts "Got it, the team is looking at this" when the tenant writes again while held.
  3. The silent decline. A tenant who says "I'm moving out" gets nothing back. Two fix PRs are in flight tonight (§7).
  4. "Send the paperwork" email on a yes (only if D3a; starts at Live) when the office owns the paperwork. Approved in principle on 10/12; shape in D3.
  5. Blocked sends are visible. A text that fails after approval records "failed" and tells nobody (an open issue on the Western Slope tracker). Page #alerts and show it on the list.
  6. Battle test on Fairhaven for 24 to 48 hours: the matrix in §10, each cell with evidence.
flowchart LR
  L["Monthly list\nKat / Jay: approve, change, skip\nby email reply or on the page"] --> C["Check before send\n(Supervised week only)\nFede + Gera, one page"]
  C --> O["Offer text + email\nto the tenant"] --> T["Tenant replies"]
  T --> H["Held reply\nSlack card + holds page\nnever expires silently"] --> S["Sent"]
  T --> X["Tool actions run at once:\nyes / no recorded; office emails\nwait for Live (the 10/10 rule)"]
  style C fill:#fff3cd,stroke:#b45309,color:#333
  style H fill:#fff3cd,stroke:#b45309,color:#333
Week 1 at Western Slope. Two human stops: their team on the list, us on every message. Week 2 removes the second stop.

Week-1 approval surface for us: the Slack card in #alerts (the mention is hard-coded to Fede) plus the staff holds page under /admin. Gera's per-message reviewer emails stay off for renewals, one list a month (Fede, 10/9). The proposed fix is two roles on one reviewer list, "decides the terms" and "approves messages", never two lists.

2. The levels

A level is a preset of three settings, in our words and our onboarding, not a fourth switch (D5). The rollout gate wraps any level for its first week. A new customer starts at level 1 unless they ask for more; Camellia is level 3 today.

LevelWho decides the termsClaraPaperworkWhat the office gets (at Live)
0 · Offnobodyrecords what arrives, says nothingofficenothing
1 · Team decides, Clara talks
Western Slope, week 1
their team reviews the monthly list: approve, change, skipoffer, reminders, replies, questions, escalationsofficethe list on the 1st · "send the paperwork" on a yes · escalation on a counter · "no formal notice yet" on a no · "needs you" at 14 days
2 · Clara also sends the paperworktheir team reviews the listsameClara in AppFolio, after the list is approvedthe list · escalations · a weekly digest
3 · Clara decides by policy
Camellia today
the renewal policysameClaraa monthly heads-up, no approval · escalations · "needs you"
4 · With the team's context
later
policy plus the team's internal notes, sent to Clara or from a meeting she joinssameClarasame as 3

3. How it fits together

Three settings the customer can see, one gate we run.

SettingValuesNew customerWho changes it
Who decides the terms newtheir team reviews the monthly list · Clara, by policyteam reviewscustomer, on the company page; per-building override
Who sends the paperwork existsthe office · Clara in AppFolioofficecustomer
What Clara knows laterpolicy only · policy plus internal notespolicy onlycustomer
Rollout gate existsOff · Supervised · LiveSupervised at turn-onPropFlow; about a week, then Live

Everything else is a rule, not a setting: the reminder cadence, which notifications go out at each level, how long a hold waits, the safety guards, the arms. §8 lists what to delete.

flowchart LR
  subgraph today["Today: one stored value, 'drafts'"]
    S1["Supervised"] --> H1["holds every message\n24 h, then dropped"]
    S1 --> L1["opens the monthly list\n(exists only here)"]
  end
  subgraph target["Target"]
    D2["Who decides the terms\n(customer setting)"] --> L2["monthly list,\nat any level that wants it"]
    S2["Rollout gate\n(ours, one week)"] --> H2["holds every message,\nnever drops one"]
  end
The consolidation. Pull the list off the gate. The gate goes back to being a soak; the list becomes a standing choice some customers keep for good.

4. Roadmap and the minimum slice per step

StepWhenMinimum sliceDone when
Supervised, level 1by Wed 10/14the six items in §1 plus Fede's four pressestheir team approved a list; we approved every message; no silent outcome for a week
Live, level 1week 2, from about 10/21flip to Live; nothing to builda full cycle: list → offers → replies → yes, no, counter each handled with the office told
Level 2 · Clara sends the paperworkwhen Jay's AppFolio templates are set per buildingthe AppFolio offer is created after the list is approved, not on day 0; list edits reach the offer and the letterone renewal signed end to end at Western Slope
Level 3 · the list becomes optionalwhen the customer asks"who decides" set to Clara; the list turns into a heads-upa month with no list edits they would have made
Level 4 · internal notesafter the company-brain decisionsnotes read when the offer is built; shown on the lease, never in the letterone month where the notes changed an offer correctly

Meeting the customer where it is: onboarding asks three questions in their words. Do you want to look at each renewal before it goes out. Does your office send the paperwork, or should Clara. Does Clara talk to your tenants. A customer may stay at any level for good; stepping up is one setting change plus one supervised week.

5. Today, and the tangle

Checked in code on 10/12 by an independent inspection; the full matrix is in §12. Three findings matter this week: one stored value drives both the message holds and the monthly list; Supervised holds Clara's words but not her actions; and several paths end in silence.

StepOffSupervisedLive
Daily check opens a renewal 90 days outskipped, nobody toldopens; the monthly list opens on the 1st and right after the flipopens; shows on the board
AppFolio offer (Clara paperwork)neverday 0, before the list is approved; AppFolio emails the tenant (per code comments, unverified); a "no" never withdraws itday 0
Offer text, email, letterrefused, stamped, nobody pagedparked until the list is decided; released at once on approve; a 24-hour hold if the lease is on no listsent on day 0
List approved with editsno listClara's words and our lease record change; the AppFolio offer and the letter PDF keep the old numbersno list
Reminders, 60/30/15-day nudgesrefusedheld; released with the list; on a 24-hour expiry reminders stop and the board says "needs you"on schedule
Clara's reply to the tenantnot sent; #alerts gets a postheld 24 hours, Slack card, staff page; then closed, the tenant hears nothingsent
Tool actions behind a held replyrefusedrun at once: yes and no recorded, escalation email sent, term change written to AppFoliosame
Office pages (no answer, 14-day signature, counter)noneall muted; the escalation email still goes, but only to the building inboxsent

What surprised us

The gate's original intent, checked against Fede's picture

Fede proposed it on 9/28 ("a mode where we're reviewing, human in the loop… for a week or a few days… then you turn it fully on"); Gera designed and built it the same week. Fede's understanding holds on intent: core modules, outbound only, about a week, then Live. Three drifts: it holds every recipient, not just tenants and prospects; nothing in code times it or ends it; and for renewals it carries a workflow, the list, not just a soak. One catch for safety: actions still happen under it. The AppFolio offer is created on day 0 and, per code comments, emailed by AppFolio.

6. What the tenant hears, what the office hears

Level 1, office sends the paperwork. "Today" is Live unless marked; Supervised adds a hold in front of every Clara line.

TenantClara todayOffice todayTarget at level 1
Yes"You're all set… our office will send over the paperwork"nothing; a "needs you" at 14 days if nothing is signed (muted under Supervised)same words; at Live the office gets one "send the paperwork" email at once (D3); in the Supervised week it is held with everything else; 14-day nudge stays
No / moving outsilence (§7); intent to vacate is recordednothing; a fallback page that Supervised muteswarm acknowledgment plus the portal notice-to-vacate link; nudges at day 3 and 7; at Live the office is emailed only if no formal notice by day 7 (D3)
Counter-offer"I'll pass that along"; never negotiatesescalation email to the building inbox only; tracked case only if the building names an ownersame words; email falls back to the company inbox; case opens at the company owner
Questionanswers from the offer block; off-offer terms escalatea timeline linesame
Silentreminders day 2 and 9, nudges at 60/30/15 days"needs you" when reminders run out (muted under Supervised)same; "needs you" shows on the board; the email waits for Live
Notice to vacate in the portalnothing more to say; the workflow ends as declinednothing from renewals; AppFolio's own automations startsame; the renewal closes and the list shows "gave notice"
Notice to vacate by email to the leasing inboxunknown; not covered by any testunknownrecorded as intent, replied with the portal link, office told; a battle-test row
STOP, then STARTSTOP blocks every text; START reopens only this company; no confirmation (open issue)nothing; an approved send then fails silently (open issue)confirmation on START; a failed approved send pages #alerts and shows on the list

Where it goes silent today

OutcomeWho hearsFix
Approved text fails at the carrier (opt-out, no line)nobody; recorded as "failed"page #alerts, show on the list (open issue)
Held reply expires after 24 hoursSlack says "the team has the thread"; the tenant hears nothingD4: re-ping, never drop
Decline reply comes out emptynobody; on a sandbox not even #alertstwo PRs tonight (§7)
No reviewers on the companythe list goes to nobody; Slack and the page onlyrefuse the flip without a reviewer
Per-building flag or an arm offnobody; the workflow records "sent"delete the flag and the arms (§8)
AppFolio emails before the list is approved (Clara paperwork; per code comments)the tenant, from AppFolio, with the unreviewed offerlevel 2 slice: create the offer after the list
Yes, office owns paperworknobody is told to send itD3
Escalation at a company with only a company inboxnobodyfall back to the company inbox and owner
Office pages under Supervisednobody (all muted)"needs you" stays as a board state; the per-tenant email waits for Live

The full notifications catalogue, 26 send sites and 29 silent outcomes, is §12-I.

7. Notice to vacate: what should happen, what happened

Expected (Fede, 10/12): "Thanks for letting us know, sorry to hear you're leaving. The next step is a formal notice to vacate in your resident portal," with the link. The portal notice is the goal because it triggers the move-out automations in AppFolio. Some tenants send it by email to the leasing inbox instead; that happened at Camellia.

What happened on 10/12: the tenant texted that they changed their mind and were moving out. Clara recorded the intent to vacate and sent nothing. Not held, nothing to approve.

Why: the decline prompt already orders exactly the reply Fede expects, one warm sentence plus the notice-to-vacate instruction, but it tells Clara to write it before calling the tool, and the delivery engine sends only what she writes after a tool returns. Her post-tool output was blank, so the pre-tool text was dropped, and the salvage step restores only links and dollar amounts. No alert fired. The accept path works because she writes after the tool. The Langfuse trace of the turn was lost too: an empty reply returns before the trace is flushed.

Fixes merged tonight, no switch (issue and two PRs in §12-H): the engine never goes silent after a tool call (a marker-only final counts as blank → send the last real draft, else the no-reply alert fires; tests fail on the old code 8 of 15, pass on the fix), and the decline prompt mirrors accept (tool first, then the reply; the subscription eval went 0 of 6 → 6 of 6). The two decline eval rows had been grading the draft the tenant never got, which is why they stayed green. Proof: unit tests with a planted defect, the renewals text eval on the subscription runner, then a live Fairhaven decline in the battle test.

Rules for the design: the notice-to-vacate link is independent of who sends the paperwork (the team path blanks the signing link; the notice link must survive). A "no" is followed by nudges toward the formal notice at day 3 and day 7. The office hears about a "no" only when the formal notice has not arrived (D3). A notice that arrives by email is recorded, answered with the portal link, and the office is told: a battle-test row, since nothing covers it today.

8. Settings: what is one, what is not

Customer settingsTodayTarget
Rent rule, terms, month-to-month premium, eligibility, auto-start dayscompany row plus building override; locked to staff after go-live, yet the building override stays open to the customerkeep; one lock rule
Who decides the termsdoes not exist; rides on Supervisednew company setting, per-building override
Who sends the paperworkexists; unset means Clara; building override has no writerkeep; unset means the office (Fede 10/12: never default to the higher autonomy level); Camellia pinned to Clara explicitly before the default flips
Reviewers (list and messages)staff-only screen; one liston the customer's settings page (Fede 10/12); two roles on one list
Renewal callon by default at runtime; the staff card shows "not set" as offone default at every door; off for a new customer
Ours (rollout)TodayTarget
Module on/off, Supervised marker, per-building rownothing stored means Livestore Off at creation; "Turn on" starts Supervised; show days in Supervised on the customer page
Company go-live stampholds email onlykeep
Not settings: delete or foldWhy
Per-building "autonomous renewal" flag, the two global arms and their env fallbacks, the auto-start armfour gates for one answer the module mode already gives; off means "recorded as sent"; Fede 10/12: never asked for the building flag. Production today: Fairhaven 9 of 11 on, Camellia 1 of 2, Willows 0 of 3, Situs and Western Slope 0; every company stores the module explicitly, so deleting the flag changes no company's state
Holdover flag plus its arm and envthree switches for one policy answer; belongs next to the month-to-month premium
Arm allowlists, rollback lists, excluded-person lists; the lapse digest flag; the module-default constantfix-shaped; the lapse digest names its own removal trigger
Reminder cadence, hold expiry, notification matrix, safety guardsrules, not choices; the cadence doc disagrees with the code (48h/5d vs 24h/7d)

9. Camellia, and the market

58
real renewal rounds, 4/22 to 9/18
24
renewed · 16 gave notice · 4 moved units · 2 month-to-month · 10 open
7 of 40
tenants who got the offer text ever wrote back
6 of 15
engaged tenants dropped after they replied

Camellia, every real renewal since launch, read on 10/12 (full report in §12-K; tenants by initials). Engagement is low, as Fede expected, and silence is not a no: 12 of the 34 tenants who never replied renewed anyway, 9 by signing the offer Clara sent. Where Clara loses is after a reply: a "yes" followed by 14 days of silence, a promised signing link that never came, a counter-offer never answered. Six tenants kept getting renewal texts after they had signed, said they signed on paper, or gave notice; one wrote "Please do not text me again". Seven things never reached the office, among them a tenant who needs Spanish and Clara saying she was "looping in" the manager when nobody was. Five households show signs of speaking Spanish and every text and call to them was in English; none renewed. The 34 calls since June produced no decisions. Since the 9/28 doc: three more signed, the AppFolio sync closed 8 stale records by itself, no new round has started since 9/18, and leases ending 11/30 and 12/31 have gone 49 to 79 days with no message.

Ranked improvements, all bugs with no switch: stop the texts once a tenant answers; keep every promise made in the thread; make every hand-off reach the office. Then: Spanish offers, drop the morning call, chase a "yes" during the 14-day signature wait.

The market (scan of 16 vendors, 10/12; full table in §12). Nobody documents a staged autonomy ladder, a supervised mode per customer, or a dark launch for renewals; that is a gap in their public material, not proof we lead. The bundled threats are AppFolio Realm-X and Yardi Virtuoso, inside the PMS the customer already uses. Worth taking: a named human backup with full context at handoff (EliseAI), hard guardrails on offer terms with an audit trail (Frontdesk), a renewal-likelihood view per resident (EliseAI), approval workflows where the manager keeps the decisions (Rentify). The words the market uses for the human in the loop: "human backup", "approval workflows", "guardrails", "transparency and control for human operators". Nobody says "supervised".

10. Testing: coverage today and the 24-to-48-hour battle test

The battle test runs on Fairhaven (the Western Slope shape) against registered team numbers only, then the Camellia regression replay stays byte-identical. Each cell gets a text, a log line or a screenshot; a cell with no evidence is red.

Tenant doesLevel 1, SupervisedLevel 1, LiveLevel 3, Live (Camellia regression)
Yesheld → approved → sent; office emailsent; office emailunchanged
No, moving outheld → sent with the notice link; nudges; office at day 7same, no holdunchanged
Counter-offerheld; escalation email; casesameunchanged
Question, then yes three turns laterheld each turnsentunchanged
Silent for the whole cyclereminders held and released; "needs you"reminders; "needs you"unchanged
Notice to vacate in the portal, then textsrenewal closed; no offer sentsameunchanged
Notice to vacate by email to the leasing inboxrecorded, replied, office toldsamesame
STOP, then STARTSTART confirmed; approved send after STOP pages #alertssamesame
Someone else answers the numbername captured, no offer details leakedsameunchanged

Office side, each with evidence: one list email to every reviewer with the hello@ copy; approve by reply; approve on the page with a rent edit and a skip; reject the list; a lease added after the list; a held reply re-pinged past 24 hours; a failed approved send; the yes email; the escalation email at a company with only a company inbox.

11. Decisions for Fede

TL;DR: hold everything in week 1 and make "who decides the terms" its own setting now; the rest are shapes of notifications and defaults. Recommendation first on each.

  1. Week 1: what we hold, who approves. Decided by Fede 10/12 evening: (b). Their team approves the list, the offer text goes out, only Clara's replies are held for engineering; nothing to build. For the record: (a) every tenant-bound message. Offers on one "check before send" page per list, replies one by one; Fede and Gera approve from the Slack card and the holds page. Cost: the check-before-send page is built Tuesday and the battle test runs Tuesday to Wednesday; nothing starts until you decide. (b) Replies only; offers go out when their team approves the list, as today. Needs only your four presses; the battle test runs on today's behavior. (c) Hold nothing beyond the list.
  2. Make "who decides the terms" a setting now. Decided (a); piece 1 #19337. Decided by Fede 10/13 (a): "reviewing the monthly list is a feature in itself, one setting: do I want Clara to just send stuff out or a review before it goes out; separate from engineering supervision." Build: setting first (default: their team reviews), then the list rides on it, then the customer-page toggle with a preview before merge. For the record (a) was: The list rides on the new setting (default: their team reviews), approval required, nothing reaches a tenant until approved; Supervised only holds messages. (b) Heads-up with a three-business-day auto-approve. (c) Leave it riding on Supervised until after Wednesday.
  3. What the office hears on a tenant answer, when the office sends the paperwork. Shipped #19333. Decided by Fede 10/13, the "yes" line: one notification through the existing notification engine ("this tenant at this property and unit said yes, they intend to renew; please prepare the lease"); building in PR feat/renewal-yes-office-notification, wording previewed to Fede before merge. The "moving out" and "counter" lines stay open. (a) Recommended: yes → one "send the paperwork" email at once; no → Clara nudges the tenant at day 3 and 7 toward the portal notice, the office is emailed only if no formal notice by day 7; counter → the escalation email plus a case at the company owner. In the Supervised week every office email here is held with everything else, so your 10/10 rule (no per-tenant staff email in Supervised) stands; they start at Live. If you want the yes-email during the Supervised week, that lifts the 10/10 rule for that one email: your call. (b) Everything in one daily digest. (c) The yes email only; nothing on a no.
  4. A held message that nobody decides. (a) Recommended: never expires; re-ping every four business hours; never auto-approve. (b) 24 hours, then auto-approve. (c) Today: 24 hours, then dropped.
  5. Levels in the product. (a) Recommended: three settings on the company page; levels are how we talk and onboard. (b) One "autonomy level" picker that sets all three.
  6. Western Slope's rent rule for the first list. Decided by Fede 10/12 evening: flat, written to Western Slope the same hour as a dollar increase of $0 (ledgered); their team edits per lease on the list. Lincoln and Courtyard are confirmed affordable housing and stay at "no renewals".

Fede's own presses before the flip, not decisions: paperwork sender to the office; Kat and Jay as reviewers; the rent rule; the flip to Supervised. The per-building flags are ours to delete or, for Wednesday, Fede's to press on the Arms tab.

Fairhaven proof, night of 2026-10-14 (production, end to end)

Every case below was run on the real production path on the Fairhaven test company (bench phone, test reviewer mailboxes). Unit tests are not counted.

Deployed: Lambdas 60c545df2, renewal worker bf71d79ae, web e45e27cf9. All carry the list email #19601, send-it-for-everyone #19649, counter note #19612, yes note #19647, plain frames #19700/#19701, and tonight's fixes #19824/#19827.

CaseResultEvidence
Monthly list email to reviewersPASSSendGrid delivered to both test reviewers; screenshot below
Reviewer opens the link, approves on the page, offer text goes outPASShold approved 21:59Z, offer text delivered 21:59Z
Reviewer replies "looks good, send it" by emailPASShold approved 22:15Z, offer text delivered
Reviewer replies "don't send X's renewal at <building> 101, everyone else 12 months"FAIL → fixed (#19827) → PASS 01:41ZClara: "approved… 101: not renewing. Everything else goes out as listed."
Reviewer replies "hold X, bump the others"PASSClara asks a fair clarifying question (rent flat or pause?), no "did you mean"
Tenant texts yes → office note sent, not heldPASSnote delivered 22:08Z, Clara's tenant reply held
Tenant counters → office note sent, Clara's reply to tenant heldPASSnote delivered 22:03Z, reply held
Tenant who owes money is on the list and gets the offer after "send it"PASS"Owes $450 on their account" in the email; offer delivered
Review page shows the owes-money row correctlyFAIL → fixed (#19824) → PASS 01:44Zrent box, Yes switch, "Going out", owes line; header matches the email
Renewals off at one building → nothing for that buildingPASS7 leases before, 6 after
The monthly list email, as delivered
The monthly list email, as delivered
The review page after approval
The review page after approval
The review page with the owes-money row, after the fix
The review page with the owes-money row, after the fix

Follow-ups filed, not blocking: #19820 (Clara forgets her own clarifying question), #19821 ("everyone else" cannot be applied by email), #19847 (approval joining a still-running offer job sends nothing, silently), #19848 (Status column clipped at 1280).

Western Slope: flip on Fede's word. Their list goes to their two reviewers; office notes for all 90 buildings fall through to the company leasing inbox.

Re-proof 2, 2026-10-15 05:28–05:40Z (after the six reply fixes deployed)

Production: web 814b3788e9, Lambdas a5908e9a16, renewal worker cba57a5193. Every case on a freshly reset October list; all 20 emails to the two test reviewer addresses; zero tenant texts.

CaseReviewer wroteExpectedObservedEvidenceResult
A1"Hold off on her renewal, send the rest"Clara asks who "her" is; question stored on the hold"Which renewal should I hold off on? Your reply says "her" but doesn't name anyone. Nothing has been changed yet." Stored on that reviewer's notice, about units 13, 101, 305 and 4 (every woman on the list). Other reviewer: none. No lease decided.hold eschold_rb_9dd95696b563b046069f7746 (cycle A, created 05:27:15Z); list email rk_5d4ef0022802365c556f0add; Clara 05:28:10Z Message-ID ce4dc843-e81b-4a57-96e3-1ceb718ac8c0@propflowai.co; pendingQuestion askedAt 05:28:10.213Z; RP2-A1-clara.eml, RP2-A1-state.jsonPASS
A2"Bump the others to 12 months" (on Clara's question)Clara asks again, naming her open question; no lease changes"I still need your answer to my question first: Which renewal should I hold off on? … Nothing applies to the others (12 months) until I know. Nothing has been changed yet." 0 decisions recorded; the question stays about 13/101/305/4.Clara 05:28:46Z e6765310-fce0-498c-b525-2ffafa682692@propflowai.co; askedAt 05:28:46.226Z; RP2-A2-clara.eml, RP2-A2-state.jsonPASS
A3"I meant <resident>, keep her flat, the others at 12 months"Named resident (unit 101) flat, every other resident 12 months, list still waiting, nothing sentClara asked AGAIN, with the text doubled: "I still need your answer to my question first: I still need your answer to my question first: … Nothing applies to the others (12 months) until I know. Nothing applies to the others (12 months) until I know. …". 0 decisions recorded, not even the flat rent. The question is now about 13, 305 and 4.Clara 05:29:24Z b66a7be6-9338-42b6-b539-7ae89e255d74@propflowai.co; askedAt 05:29:24.088Z; RP2-A3-clara.eml, RP2-A3-state.json; raw model output in RP2-replays.txt (correct: keep_flat on the named resident + "the others" set_term 12); offline repro RP2-repro-a3.txtFAIL (defects 1 and 2)
B"Bump the others to 12 months, <resident> stays as proposed" (fresh list)Brief: named resident unchanged, the others 12 monthsClara asked "Should <resident> at <building> 305 also get 12 months? Nothing applies to the rest until I know. Nothing has been changed yet." 0 decisions. The model writes no instruction for "stays as proposed" (3/3 replays), so the code asks.list rk_1dc63dba2e1347f5374b21bb; Clara 05:30:52Z 9240f2d6-3ec3-4dd6-b250-c975588b45b8@propflowai.co; question about unit 305 only; RP2-B-*.eml/json, RP2-replays.txtDIFFERS FROM BRIEF, matches the merged design. Safe: nothing applied, nothing sent.
C1"Everyone at 12 months except unit 305" (the email shows "Unit 305")Clara asks about that one resident only (merged test: "Should X also get 12 months?")"Should <resident> at <building> 305 also get 12 months? Nothing applies to the rest until I know. Nothing has been changed yet." Only 305 asked about (unit 101 is in the same building and was not). 0 decisions.list rk_e9496ea02e00dd3b21383ca7; Clara 05:32:19Z fc83b8a3-3a86-4d5e-bba7-8c19de24083f@propflowai.co; RP2-C1-*.eml/jsonPASS (asks, never applies)
C2"Everyone at 12 months except number 305" (fresh list)SameSame question, word for word, about unit 305 only. 0 decisions.list rk_cbb5136ba743bd0086035c40; Clara 05:33:45Z 682d2951-849f-4af0-a01f-b29ce3c354d7@propflowai.co; RP2-C2-*.eml/jsonPASS
D"Don't raise the others, send" (fresh list)"Should the rest of the list get <change>?", nothing sent"Should the rest of the list get a flat rent? Nothing has been changed yet." List still pending, 0 decisions, no send. Stored question names no one (leaseIds []).list rk_c634a2da58e9f151fdf1d376; Clara 05:35:11Z 71a657a4-711a-4844-b0c8-b61d88fd05f7@propflowai.co; RP2-D-*.eml/jsonPASS
E"Everyone at 12 months, send" (fresh list)Approve, 12 months for all, no question"Thanks, approved. What I changed: [7 rows]: 12-month term. Everything else goes out as listed." Hold approved 05:36:30.835Z by the reviewer. 6 rows approved with termMonths 12. The Fede-phone row stayed struck (renew false). Scan 05:36:51Z: TEAM-APPROVED for the balance-held test tenant, new saga saga_d2ed7a6f-898d-42f7-a4ee-8c3936c93f80, per-lease workflow run 01a13e10-32d8-7f36-9aa6-add39760034d. 05:36:53Z "deferring outreach to next send window, source: quiet_period" (23:36 local). No text yet; it goes to the bench in the morning send window.list rk_9e83ee36afdfdc06e651d8b5; Clara 05:36:32Z ae6c7026-cb42-4219-9394-8fe3aa853529@propflowai.co; RP2-E-*.eml/json; renewal worker log /aws/ecs/propflow-renewal-worker-prod 05:36:51–53ZPASS. The offer text is correctly held for quiet hours, so that part is not proven tonight.

Defect found by A3: when Clara's question lists several possible residents, naming one of them does not count as an answer and each re-ask nests the previous one. Fixed in #19943 (no switch) and re-proven live below. Leftover: the "Recorded" email still lists the struck row as "12-month term", filed as #19942. Case B: 'stays as proposed' makes Clara ask rather than apply; matches the merged design, kept.

Re-proof 3, 2026-10-15 07:50–07:53Z (after fix #19943 deployed)

Production: merge b2d48c2a6 on web, Lambdas and the renewal worker. Same reset, same test reviewer addresses, zero tenant texts.

CaseReviewer wroteExpectedObservedEvidenceResult
A1"Hold off on her renewal, send the rest"Clara's "which one?" question"Which renewal should I hold off on? Your reply says "her" but doesn't name anyone. Nothing has been changed yet." Saved about units 13, 101, 305 and 4. No decisions.list rk_50ca93e8e5de69e3b9906684; Clara 07:50:40Z be969620-0ac5-4073-91da-4bdc009889a3@propflowai.coPASS
A2"Bump the others to 12 months"One re-ask, original question once, not nested"I still need your answer to my question first: Which renewal should I hold off on? Your reply says "her" but doesn't name anyone. Nothing applies to the others (12 months) until I know. Nothing has been changed yet." One lead-in, question once. No decisions.Clara 07:51:03Z e1af0e47-5a2a-49fa-aaf7-7088d11979aa@propflowai.coPASS
A3"I meant <resident>, keep her flat, the others at 12 months"That resident flat (recorded), every other resident 12 months, question closed, nothing sent"Recorded: <resident> at <building> 101: rent stays $2,395. [6 others]: 12-month term. The list is still waiting for your approval…" Unit 101: renew true, rent 2395. Units 13, 1460-4, 305, 4, 1254: termMonths 12, still pending. The struck test row stays struck. Question cleared. List pending, no send.Clara 07:51:38Z 19ba1e51-a180-4871-a66d-566a569fa668@propflowai.co; decisions at 07:51:38.7–.8ZPASS (the struck test row is still listed as "12-month term": known minor, #19942)
A4Fresh list. A1 again, then "I meant <resident>"Her renewal held off (the original instruction); no change for the restA1: same "which one?" question (Clara 07:52:46Z 92d9ec24-0f6c-46b1-942f-05fd1c4daf0d). Reply 2: "Recorded: <resident> at <building> 101: not renewing. The list is still waiting for your approval…" Unit 101 struck (renew false). Every other row pending with no decision. Question cleared. No send.list rk_afacf011a58a6a7ae46d6ccb; Clara 07:53:18Z 3f61de7c-1ec3-4683-a334-cdb5f725ee72@propflowai.coPASS

Re-proof 4 (2026-10-15): deploy checks and readable office notes

Run on production Fairhaven after the fixes deployed; every reply came from the bench number and every email went to a test address.

CheckResultEvidence
Defect 2 re-proven live after deployPASSreport-reproof2.md, Re-proof 4 check 1
Defect 3 and defect 8 re-proven live after deployPASSreport-reproof2.md, Re-proof 4 check 2
3a. Offer text goes out at 8 AM Mountain, not during quiet hoursPASStext SMe48ba4ea425fead17a35798f2829ce4d at 14:00:13Z
3b. Counter by text → office note "countered their renewal" quotes the counter and our offer, agrees to nothingPASSRP4-counter-note.png; note id c2c97571-cb4e-45a9-9eea-d1d9d2bab7ba
3c. Clara's reply to the counter held, not sentPASSeschold_0632ce5d-76a5-47fe-9a72-ff4e49489b01
3d. Yes by text → office note "said yes — please prepare the lease" with rent, term and start datePASSRP4-yes-note.png; note id 77d10fb1-2dc3-4e2a-a76d-8cbbe9f1a854
3e. Both notes use the coworker-note frame (one sentence, "Open the renewal" link, signed Clara, small logo, no footer)PASSsame two screenshots
3f. Fairhaven reset: list waiting, no running workflow, nothing queued to the bench, office email restoredPASSRP4-final-state.json
Follow-ups filed, not blockers🟡#20003 (a yes after a counter leaves the record in review), #20004 (no holding text after a counter)
Office note after a counter
Office note after a counter
Office note after a yes
Office note after a yes

Month cards (shipped 2026-10-15)

Fede saw the prototype and said go (2026-10-14 night); legend dropped (not asked for). Shipped as PR #19881, merged 03:25Z, in production by 04:38Z. Verified live, headless screenshot of the real renewals page at 04:40Z (cards only shown; the list below them carries resident names).

Month cards live in production
Live, 2026-10-15 04:40Z: 0% on every month, equal heights, no legend
Month cards live at phone width
Live at phone width

Prototype record, for the trail:

BeforeAfter
Big number— / 0% / — / —0% on every month
Card heights137 / 167 / 137 / 137 pxequal (167 px)
Month cards before
Before: dash when nobody has answered yet; the November card is taller
Month cards after
After: 0% everywhere, equal heights
Phone width before Phone width after
Phone width, before and after

Why the dash existed: the renewed % only counted people who had answered; with no answers it was blank and drew as a dash. The fix shows 0% until someone renews. The renewal rate used elsewhere is unchanged.

12. Reference (for agents)

Written for an agent. Every claim carries its source; nothing is summarized. Line numbers are from the 10/10 checkout c383d08ff0 unless noted; origin/main is ahead, and only one row changed (the "team is looking at this" text, #18564).

A. Mode matrix, every step, Off / Supervised / Live (Opus inspection, 10/12)

File key: AS renewal-auto-start.ts · WF workflows/renewal-workflow.ts · ACT activities/renewal.ts · TR/ER/RR renewal-orchestration/renewal-{text,email,reply}-review.ts · TOOLS agents/clara/lib/agent/tools/renewal/handlers.ts · SB/OB/ST/BGATE/RLR renewal-batch/{scan-batch,open-batch,settle-batch,batch-gate,release-render}.ts · HT/HRE/BG escalation/{held-text,held-reviewer-email,bake-gate}.ts · NOTIFY leasing/renewal-notify.ts · JOBS integrations/sqs/agent-jobs.ts · TW integrations/twilio/client.ts · VOICE integrations/voice/initiate-outbound-call.ts · SCS escalation/supervised-call-state.ts · CHAIN modules/building-module-chain.ts · SRH modules/supervised-reply-hold.ts · PE agents/clara/lib/messaging/process-envelope.ts · HOLD leasing/renewal-holdover.ts · REM leasing/renewal-reminder-sms.ts · SMS leasing/renewal-sms-template.ts · PMSW pms/writers/renewal.ts · LR app/api/leases/[leaseId]/renewal/route.ts · RECAP renewal-orchestration/recap-sms.ts.

Modes in code: Off is an explicit false for leasing.renewals (company switch, building row {enabled:false}, or building not in PropFlow). A company with nothing stored is Live (is-module-enabled-for-org.ts:41-43). Supervised = on plus a 'drafts' marker at company or building (:99-107; write-building-module.ts:15-21). Both need the auto-start arm (AS:414-430), the building opt-in (AS:765-772), the sending arm plus autonomousRenewalEnabled, checked before any Supervised hold (ACT:830-857). Held = saved for approval; parked = held until the list is decided, no 24-hour timer.

#OffSupervisedLive
1 Daily checkskips the building; nobody told (AS:719-735, 797-803)opens as Live; monthly list once a month and right after a switch into Supervised (AS:737-760; OB:35-44; renewal-flip-scan.ts:1-9); list to reviewers by email plus Slack and the page (OB:46-62; HRE:101-112); month-to-month never on it (SB:144-145)starts inside the window; board only (AS:2072-2260)
2 AppFolio offernever (JOBS:251-270)Clara paperwork: day 0, before approval, robot prepares and sends to the portal (AS:2257-2259; JOBS:313,360,586); no Supervised check (JOBS:251-284; ACT:2896-2945); comments say AppFolio emails the tenant (pms-adapter.ts:474; AS:1857-1859). Team paperwork: never; PropFlow saves its own offer (AS:2140-2160; WF:3113-3115, 3334)same, per sender
3 Offer textrefused at the door, stamped held_module_off, nobody paged (ACT:1108-1125; TW:1077-1100)held; parked with no expiry if on a pending list (TR:94-110; held-message-rule.ts:64-76); released at once if the list is approved (TR:112); plain 24-hour hold if on no list (TR:100-111); Slack (building channel → company → #alerts) and the page only (BG:179-210; HRE:105-108)day 0 outside quiet hours (ACT:815-1000)
4 Offer email, letterrefused, stamped, no page (ACT:2044-2089, 2344-2368)same hold and park (ER:56-90; ACT:1906-1911, 2242-2290); on release the words are rewritten but the AppFolio letter PDF saved with the hold stays attached (RLR:119-130); email only to tenants with no phone (renewal-channels.ts:56-63); letter only under Clara paperwork (WF:3741)day 0 (ACT:1758-2400)
5 List approvalno list (SB:70-92)approve: rent/term/concession written to the lease, parked messages rewritten and released (ST:14-61; RLR:52-152); "no" on a lease closes its parked messages as rejected (ST:66-97; BGATE:69-90); reject the list rejects all (ST:44-50); none touch AppFolio; a settled list takes no more decisions (ST:84)no list
6 Reminders day 2/9, 60/30/15-day nudges, MtM warningrefused for a running cycle, nobody paged (ACT:1612-1621)each held (ACT:1473-1505; WF:3961-4133); released with the decided numbers if the list was approved (TR:112; ST:29-40); else 24-hour hold; on expiry reminders stop, board "needs you", PM page muted (WF:4178-4190; NOTIFY:251-292); on reject same with no page (WF:4191-4201); the scan's MtM warning is re-held after an unapproved expiry (AS:2765-2811)on schedule
7 Term change, portal linktools refuse (TOOLS:519-527)portal link, recap, after-call recap: 24-hour hold not tied to the list (TOOLS:376-399; RR:92-125; RECAP:254-276); term change under Clara paperwork writes the lease and AppFolio at once, only the text is held (TOOLS:1805-1880; LR:930-960); under team paperwork handed to the escalation tool (TOOLS:1748-1761)sent at once (TOOLS:401-422; LR:962-980)
8 Clara's replynot sent; #alerts post naming the building (RR:166-171, 217-260; TW:1086-1093)held when about the renewal, routed to Renewals, or the topic check fails or exceeds 6 s; general replies send (SRH:1-40, 103-131; classify-reply-topic.ts:146-190); texts held for everyone except staff (PE:402-423); emails only at a company marked live (SRH:69-90); newer reply supersedes (RR:208; held-reply-supersede.ts:18-27); after 24 h closed, Slack "the team has the thread", tenant gets nothing (HT:457-472); main adds "Got it, the team is looking at this" on a second text (#18564)sent
9 Tool actions behind a held replyrefusedrun at once: yes/no saved and signalled (TOOLS:605-687, 948, 992-1040); escalation emails the building inbox (TOOLS:1095-1141); term change to AppFolio (TOOLS:1805-1880); only the texts are held (TOOLS:376-399)same, texts send
10 Yes, then 14-day signature waitrefusedyes saved; no PM email (TOOLS:961-963); once AppFolio shows the tenant signed, PM gets "ready for your signature" reminders, not stopped by Supervised, only sandboxes skipped (pm-action-reminder-renewal-bridge.ts:34-87; pm-action-reminder-copy.ts:186-201); no countersignature in 14 days: board "needs you", page muted (WF:1970, 2097-2164); #18548 mutes only the scan's held-renewal page (page-pm-for-held-renewal.ts:103-112)same plus the 14-day page by email and text
11 Norefusedintent and reason saved; workflow ends "intent to vacate" (TOOLS:992-1040; WF:2238-2240); no PM email, no AppFolio write (TOOLS:1052-1054); Clara points to the portal notice (TOOLS:1047-1050); fallback page muted (renewal-decline-delivery.ts:254-266)same; fallback page goes
12 Counter or unanswerable questionrefusedemail only to the building's own inbox, no company fallback, not stopped by Supervised (TOOLS:68-91, 442-452); case only if the building names an owner (TOOLS:1144-1166, 1203-1209); workflow escalation page muted (TOOLS:1353-1355; WF:2262-2264); a plain question adds a timeline line (TOOLS:852-920)same email and case; the workflow page goes to renewal contact → building inbox → company owner, plus a text (NOTIFY:127-142; pm-contact-email.ts:96-133)
13 Renewal calldoor refuses, no retry (VOICE:446-449; ACT:2744-2750)per-module choice; "calls go to the team" (default when unset) = no call; "Clara answers calls" dials on day 0 before the list is approved (SCS:1-50; VOICE:490-521; WF:3897-3905); recap text held (RECAP:254-276)dials day 0 unless voiceCallEnabled is false; on by default (renewal-channels.ts:50-55; ACT:2521-2620)
14 Month-to-month rolloverskipped (HOLD:149)needs proof the warning reached the tenant; the warning is held so the rollover waits; then AppFolio is written with no further approval (AS:2765-2811; HOLD:179-188); office notice follows the Team notices module (renewal-holdover-notify.ts:151-180)rolls over when armed (HOLD:91-95); under team paperwork never written (HOLD:84-90)
15 AppFolio syncsame in all modes and senders: "Renewed" closes, "tenant signed" updates, "prepared" fills an empty offer; never reads mode or sender (PMSW:45-75)
16 Notice to vacate filedall modes; the workflow ends "declined" or a declined record is created (NTV:1-35, 139-150); nobody at the customer emailed; an unmatched notice alerts engineering once a day (NTV:58-72)
17 Send-door backstoprenewal-send-guard.ts only stops double sends; Off refused (TW:1077-1100); Supervised refuses an unapproved resident text and alerts engineering (TW:1124-1150); email door same (company-live-gate.ts:435-466); voice same (VOICE:490-521); if the mode can't be read, the message sends (TW:1127-1129)
18 Per-building overridecompany Off is a ceiling (CHAIN:170-183)under an "on" company the building row wins; a building "On" is Live under a Supervised company (write-building-module.ts:15-21; CHAIN:196-248)switching a building Off mid-cycle doesn't stop the workflow; later messages refused and stamped, tools refuse, replies post to #alerts (ACT:1108-1125; TOOLS:519-527; RR:166-171); a failed AppFolio prepare pages nobody and closes the cycle (ACT:3053-3057, 3844-3851)

Unverified by the inspection: that AppFolio emails the tenant on prepare (code comments only); what happens to messages already held when a building is switched Off; what Clara tells the tenant when the escalation reached nobody; whether customer staff can see the PropFlow Slack channel.

B. Clara vs the office sending the paperwork
ItemClara (default)The office
Settingbuilding first, then company; unset means Clara; locked for the cycle at start (paperwork-sender-chain.ts:1-23, 128-135; TOOLS:1742-1748); a failed read returns null and the robot runs (:142); the building rung has no writer (:185)same
AppFolio prepareday 0, prepared and sent to the portal (AS:2252-2259; JOBS:313,360)none; PropFlow saves its own offer and treats it as prepared (AS:2140-2160; JOBS:271-284; WF:3113, 3334)
Every signer needs an emailyes, for the portal inviteskipped (AS:1856-1867)
Offer text"Review and sign in your resident portal: [link]" plus a letter line"Our office will send over the renewal paperwork for you to sign" (SMS:55-62)
Reminders, nudges, MtM warningportal link"…our office will send over the renewal paperwork…" (REM:33, 105-165, 235)
LetterAppFolio PDF by textnone; "Resend letter" refused (WF:3741, 2582-2586)
Term changelease write + AppFolio term change + confirmation textescalation tool with the requested term (TOOLS:1748-1801)
Month-to-month rolloverwritten to AppFolio when armednever written; warnings still go (HOLD:84-90)
Close-outAppFolio syncidentical (PMSW:45-75)
14-day PM reminders"…agreed to renew… just needs your signature" (pm-action-reminder-copy.ts:186-201; WF:2157-2163)identical wording
Reply promptsigning step in the portal"the office will send over the renewal paperwork", no portal step (#19039, merged 10/12); the send_offer_sms recap still appends a portal link (#19041)
C. Settings inventory: every key, where it is set, what reads it (Sonnet inspection, 10/12)

No renewal block in org.settings (data/types.ts:15460-15489). Company renewal policy lives in registry rows ATTACH#setting#renewal.*. The arm row CONFIG/RENEWAL_ARMS is one row for all customers.

KeyLevel, type, defaultSet where (who)ReadClass
renewal.offerTerms (rent rule, max increase, terms, mtmPremium)company registry (registry/keys.ts:1209-1238) + building RENEWAL_POLICY# row; absent = refuseonboarding RenewalOffersQuestions → PUT /api/settings/renewal-policy, customer until go-live then 409 (route:119); /settings/renewals read-only (client-page.tsx:51); staff RenewalPolicyCard.tsx:122; building editor PropertyDetailClient.tsx:818 → PATCH /api/properties/[id]/knowledge, customer, no lockfoldRenewalPolicy company-chain.ts:116 (building wins; broken building never inherits :197); facts.ts:400policy
offerTerms.voiceCallEnabledbool; absent = On (facts.ts:189-206)staff card; building editor RenewalPolicyEditor.tsx:539; onboarding never asks; not on /settings/renewals (managed-settings.ts:59-85)renewal-channels.ts:46capability
renewal.eligibilitycompany registry (:1239-1259) + building row; four different balance defaults (facts.ts:33-41)same doors; maxAccountBalance never asked (renewal-drafts.ts:69-80)company-chain.ts:116, :209policy
renewal.autoStartDays → building renewalAutoStartDaysBeforeLeaseEnd → legacy renewalOutreachInitialDaysint; 90; company 14-180, building 1-365company only via the PUT; building /settings/renewals → POST leasing-settings, customerrenewal-auto-start-chain.ts:83; renewal-auto-start.ts:483, :503policy
renewal.paperworkSendercompany registry (:1276-1291) + building rung; 'clara' | 'team'; default claraonboarding or Settings, customer before go-live; staff card :110; building writer has no callers (paperwork-sender-chain.ts:185)paperwork-sender-chain.ts:128-135; refuseIfPaperworkSentByTeam :167-178policy
heldMessageReviewers['leasing.renewals']org.settings (data/types.ts:16242); staff or vendors; emptystaff only: PUT /api/admin/companies/[id]/held-message-reviewers (ModuleReviewersRow.tsx:38, :99)held-message-reviewers.ts:29-34; scan-batch.ts:177policy
Reminder cadence D+2/D+9, nudges 60/30/15code constant; the doc at renewal-workflow.ts:949-961 says 48h/5dnowhererenewal-workflow.ts:3935-3936, :4086-4093; followup-registry.ts:428-449 'fixed'rule
renewalContactEmail / renewalContactPhonebuilding leasing settings (:17324, :17327); email falls back to propertyEmailno UIrenewal-notify.ts:127-131; pm-action-reminder.ts:512policy
renewalExecutionCcEmailsbuilding (:17364)/settings/property, customerrenewal-execution-notify.ts:122-132policy
Letter MMSno key; always firesnothingrenewal-channels.ts:1-23capability
Monthly listno key; rides Supervisednothingscan-batch.ts:71-77; batch-gate.ts:28capability
enabledModules['leasing.renewals']org.settings (:15498); absent → platform row → all onstaff: /admin/customers/[id] → /api/admin/modulesresolve-module-entitlement.ts:144rollout
moduleModes[...]='drafts' + moduleSupervisedCallsorg.settings (:15511, :15549); absent = Live; calls absent = 'team'staff, same dooris-module-enabled-for-org.ts:99-107; resolve-module-entitlement.ts:318-340rollout
leasing.renewals.module + building.in_propflowbuilding registry (:1176-1197); absent = inheritstaff (building-switches.ts:166) or scripts; customers only during onboarding (:151)building-module-chain.ts:160; renewals-entitlement.ts:47rollout
claraLiveorg (:16079); must be exactly truestaff: PATCH /api/admin/companies/[id]/clara-liveclara-live.ts:240; email only (email/client.ts:1570); locks the company policy (route:119)rollout
autonomousRenewalEnabledbuilding flag (:3960); falsestaff Arms tab /admin/dev/access-inspector?tab=arms → PUT /api/admin/arms; the editor toggle was removed (RenewalPolicyEditor.tsx:665-670); the knowledge PATCH writes only an audit copy (dynamo/renewal-policy.ts:113-119)renewal-auto-start.ts:497; autonomous-gate.ts:67; skipped when a PM opened the renewal (activities/renewal.ts:200-202)fix-shaped
Arm autonomousSending + env RENEWAL_AUTONOMOUS_SENDING; arm autoStartarm row (:17682, :17677) + env; falsescripts/set-renewal-arms.ts; Arms tab read-onlyautonomous-gate.ts:42, :58; activities/renewal.ts:831, :853; arm-store.ts:163; renewal-auto-start.ts:423fix-shaped
autonomousHoldoverEnabled + arm holdoverConversion + envbuilding flag (:4175) + arm (:17680) + env; falseflag: Arms tab; arm: scriptrenewal-auto-start.ts:502, :1525-1556; holdover-gate.ts:36, :52fix-shaped
Arm lists: workflowOwnedDispatch.propertyAllowlist, stableWorkflowIdentity.rollbackPropertyIds, autoStartExcludedPersonIdsarm row (:17703, :17747, :17816)script onlyarm-store.ts:237, :281, :216; renewal-auto-start.ts:716, :775-785fix-shaped
Schedules renewal-auto-start-daily, renewal-cohort-walker-dailyTemporal pause statescripts/temporal/upsert-renewal-auto-start-schedule.tsconfig/automations.toml:297-324fix-shaped
renewalLapseDigestEnabledbuilding (:17357); false; names its own removal trigger (:17351)scripts/set-property-lapse-digest.tsrenewal-auto-start.ts:635fix-shaped
RENEWALS_MODULE_DEFAULT_ENABLEDcode constant true; repeats the registry defaultn/arenewals-module-route.ts:76, :100, :125, :140fix-shaped
Env: RENEWAL_ARM_CACHE_TTL_MS, RENEWAL_TASK_QUEUE_OVERRIDE, ELEVENLABS_RENEWAL_AGENT_ID, TWILIO_MESSAGING_SERVICE_SIDenvdeployarm-store.ts:58; temporal/client.ts:139; renewal-worker.ts:105; initiate-renewal-call.ts:59-61; activities/renewal.ts:2215fix-shaped
Test gates: phone-registry kinds, TEST_PROPERTY_IDS, DARK_FEATURE_BENCH_IDS, isTestcode + configcode change onlytest-scope-recipient-guard.ts:46, :78; test-property-ids.ts:79, :122, :132; renewal-auto-start.ts:1189-1197fix-shaped

Override semantics: module On/Off, the company is a ceiling (resolve-module-entitlement.ts:216; building-module-chain.ts:174-184); Supervised vs Live is not a ceiling, the nearest row wins (building-module-chain.ts:204-209, 240-247; write-building-module.ts:86-94); staff "Turn on" starts Supervised (module-row-actions.ts:74-94). Not switches: patched() replay markers; the per-renewal PM pause (activities/renewal.ts:213); renewalHorizonDays (display); Lease.evictionPending (no writer). Retired: RENEWAL_AUTO_START_ENABLED, TEMPORAL_ACTIVITIES_EFFECT_MODE, TEMPORAL_LIVE_PROPERTY_ALLOWLIST, RENEWAL_OUTREACH_KILL_SWITCH.

Production reads on 10/12 (read-only probes, scratchpad ws-ready/a.ts, d.ts, e.ts): Western Slope org_c42d9150… module enabled=false, stored mode null, company policy {rentStrategy market, terms [12], mtmPremium 150, voiceCallEnabled false, autoStartDays 90, paperworkSender null}, 90 buildings all state=off, line +19708220641 everywhere, PM inbox leasing@westernslopepm.com everywhere, reviewers [], claraLive true, moduleSupervisedCalls {maintenance: live}, autonomousRenewalEnabled true on 0 of 90, holdover flag 0; arm row {autoStart true, autonomousSending true, holdoverConversion true}; Camellia's one building has the flag on. Logins at Western Slope: 8 (Kat and Jay among them).

D. The Off / Supervised / Live gate: origin, design, build, drift (research on raw transcripts, ADRs, PRs; 10/12)

Origin. 9/28 standup (#transcripts, raw), Fede: "besides on and off there's also another layer… a mode where we're reviewing, human in the loop… for a week or a few days we're still reviewing every reply, that's what I did with leasing… then you turn it fully on… i don't know long term we're gonna continue to do that." Same thread Fede asked to centralize module flags; Gera: on/off "is not a simple binary"; Gera's Gatekeeper design that day: "the 'few days of review' step used when leasing launched". Trail: ADR-0139 (accepted 9/28, amended 9/29 and 10/1, the name "Supervised"); drafts design page 9/29 (decision b90675488); Gera's PRs #13909, #13903, #13906, #14894. Ancestors: collections approval gate (ADR-0125, 8/6), renewal review switch (#13009), Camellia bake gate (#6654, 8/30, "TEMPORARY").

Designed. Only what goes out waits ("anything inbound we always record", Gera 10/5); actions happen right away, only the message waits (Gera 10/1). "Someone on the customer's team presses send" (design 9/29; 10/4 announcement); Gera 10/6: "goes through our Slack, and then we can just thumbs up it". Expiry 24 h then it dies unsent; a newer draft replaces the older (Gera 9/29, "a little bit of urgency" 10/5). Calls cannot wait: Supervised treats a call like Off unless "Clara answers calls". Length "about a week" (Gera 10/5); Fede 9/30: "first week it's supervised… we review it on Slack, click approve, send it". Optional: "we can skip it… go straight to live" (Gera 10/6). Exit: no rule; staff press "Make Live". The onboarding playbook's older review-mode bar: replay shows 0 "do not send", 90% sent as-is, Fede decides.

Built (10/10 checkout). Only 'drafts' is stored (types.ts:15511); six modules honor it (drafts-allowed.ts:34-38). Holds every automatic message to a person: residents, prospects, vendors, handyman, crew, owners, staff notices (AdminBuildingsCard.tsx:58; supervised-reply-hold.ts:103-155). Never held: emergencies, urgent jobs, person-started messages, approvals, escalations, login codes, general replies. Approve re-checks, sends through the normal door with an approval id; the door refuses unapproved Supervised sends (drafts-backstop.ts:16-54). Only a stored Supervised holds; an unreadable setting sends (resolve-module-entitlement.ts:296-298). 24 h expiry (held-message-max-age.ts:17); MtM warning re-held with a fresh 24 h (renewal-auto-start.ts:2797); renewal-list items never expire (held-message-rule.ts:73). Slack card to the building channel else #alerts (bake-gate.ts:197-209); mention hard-coded to Fede (review-gate-mention.ts:26) until per-module customer reviewers (ADR-0141, 10/8). Company plan is a ceiling for Off only (building-module-chain.ts:177-183); a building Live beats a company Supervised (building-module-override.test.ts:294); staff "Turn on" starts at Supervised; customers see only on/off.

Drift. Scope: "anything that goes out to tenants" (Gera 10/6) became "every recipient" (10/4). Reviewer: announced as the customer's team, built as PropFlow staff; customer reviewers came 10/8 (ADR-0141), only staff set the mode. "Short" not enforced: no timer, no since-date, no nudge, no exit rule; standing Supervised on both test companies (testing playbook 10/9) and Collections "nobody on Live" (Gera 10/1; 0 Live / 77 Supervised on 10/2). Renewals ride on the state by Fede's 10/9 ruling: the list opens only in 'drafts' (scan-batch.ts:77, #18321); per-message reviewer emails off (held-reviewer-email.ts:108); PM paging off (#18548, #18552). Long-term talk: Fede 10/8, right after "eventually we'll not have that": customer reviewers are "more scalable, I think, long term… we would probably want that client too". Two hold systems share one queue: company "review mode" (Fede 9/19, "TEMPORARY") and per-module Supervised; mixed up in #western-slope 10/7. Regression: team notices defaulted to Supervised 10/4-10/6; Fede 10/6: "Camellia should be fully autonomous"; default now Live (types.ts:18530); stale comments remain (drafts-allowed.ts:32, types.ts:15552).

Verdict on Fede's five claims. Core modules: mostly (four core plus two send modules). Tenants and prospects: partly (every recipient). A week then Live: yes on intent, nothing in code. Temporary: yes for new modules; standing exceptions Collections, test companies, the renewals list; skippable. Outbound only: yes, inbound always recorded; catch: actions still happen. Suggested, not asked: decide whether Supervised is a timed soak (show days-in-Supervised) or a standing mode (then name the renewals list and Collections separately). This page takes the first.

E. The empty decline reply: diagnosis (Langfuse and code, 10/12)

Langfuse keys: Keychain service propflowai-prod (LANGFUSE_*). The 20:50Z text turn has no trace 23 minutes later; the email thread in the same minute has three. Likely cause: the flush at conversation-manager.ts:17421 is fire-and-forget and an empty reply returns the Lambda at once. The 7 "renewal_declined" hits since 9/1 are false positives (thinking text only); no traced text decline exists to compare. Control: the 20:42 "yes" turn (traces d22739cb, 83f66c1e): call 1 thinking plus renewal_accepted, no text; tool result {success:true, intent:"renew"}; call 2 "That's great news… You're all set for the 12-month renewal at $914/mo…" (the test tenant's prepared offer on Fairhaven). So tool-result wording is not the cause.

The conflict only decline turns have: prompt.ts:191 "Write your response TEXT first (before calling any tool)" and :198 "The text must appear BEFORE the tool call"; clara-delivery.ts:167 "text alongside a tool call… is NOT sent… Only your response AFTER all tool calls complete is delivered"; :173 the decline instructions "before going silent". Where the text dies: conversation-manager.ts:13888 restores the pre-tool text only if the final is exactly empty; a marker-only or whitespace final counts as non-empty; the salvage guard restores only URLs and dollar amounts; the strip at :13941-13942 blanks it; nothing re-checks. No NoReplySent log line, so the 13915-13918 branch did not fire. Not deliberate silence: no end_conversation (:13150), no guard CRITICAL; the video-only silent rule is at :13913. alertNoReplySent posts to #alerts through pageFede once per hour per conversation and cause; on a sandbox it is a console WARN only. Outcomes by post-tool output: exactly empty → pre-tool text sent; marker-only or blank → silent (this case); a short closer → sent without the notice instruction; a full rewrite → fine. The CI eval (evals/promptfooconfig-renewals-sms.yaml) is one model call with only the renewal block and cannot see this. Fixes: (A) prompt.ts:187-198 tool first, then the reply, keep the "AFTER A DECLINE" heading for renewal-prompt-block.test.ts:105-150, update the two decline cases in evals/datasets/renewals-sms.yaml:2655+; (B) conversation-manager.ts fallback on the cleaned text, then the last pre-tool draft, else noReplyAlert('empty_reply'); (C) await flushLangfuse briefly on the empty path. Scratch: scratchpad/lf/.

F. Evidence from the 10/12 Fairhaven end-to-end rounds
  • Monthly batch id (deterministic, Fairhaven, October): eschold_rb_9dd95696b563b046069f7746. Holds renewal_outreach_sms parked for the batch; approval signals the per-lease Temporal workflow renewal-lease-sbx-53047a062c494231-<leaseHash>-<endDate> with heldTextDecision; sendOutreachSms returns dispatched | dispatched_failed | held_for_review.
  • List email: one send, To = every eligible reviewer, hello@ BCC (copyObserver, skipped on test-scope companies), one reviewerNotices entry per reviewer sharing replyKey (#19010, merged 52685b951). Plain-note layout with the small bottom logo (#19009, merged 27dc2eeda); "Review the list" link below the lease rows (#19032, armed 20:33Z).
  • Approval by page (rent edits, strikes) and by email reply ("approve") both proven; tenant offer text and email delivered to the registered test phone and inbox.
  • 20:26Z: approved text not delivered; cause a carrier opt-out from 9/17 ("Cancel") with scope=all on the test phone; START to the Fairhaven line +17208071724 at 20:36:34Z lifted it for Fairhaven only (ruling b91487274); round-5 text delivered 20:40:43Z (SID SMeecc5759…). Nobody was told about the failed send: #18573, on the Western Slope tracker as ws-renewals-silent-send-failure-2026-10-12.
  • 20:42Z: tenant "yes" → renewal_accepted → reply held (clara_reply_sms, eschold_4ad11cde…), Slack alerts card only; approved by hand; reply delivered.
  • 20:50Z: tenant "changed my mind, moving out" → renewal_declined recorded → empty reply (log "No outbound for envelope … empty reply (suppressed by agent loop, e.g. runaway-ceiling stop)"); runaway ceiling did not fire. Conversation conv-renewal-sbx-53047a062c494231-95b4f72a5105-saga_64245c21-1460-4525-b330-b51661bf13a6.
  • Copy rulings: "Reply STOP to opt out" footer removed from renewal texts (#19038; "this is not marketing"); the office-paperwork line "Our office will send over the renewal paperwork for you to sign — reply with any questions" (renewal-sms-template.ts:56-62); the reply prompt follows paperworkSender=team (#19039, merged 1f1a12520); recap still appends a portal link under team (#19041).
  • Western Slope dry run (ws-ready/c.ts, 10/12): 18 leases on the first list, 12 would send, 6 held by eligibility.
G. Competitive scan, 16 vendors (web research, 10/12)
ProductDecides termsSendsHandles repliesPaperworkHuman in loopIntegrations
EliseAInot stated; offers via branded portal30/60/90-day touchpoints; SMS, email, voiceanswers; "hands off to staff with full context preserved"e-signature "runs automatically"no approval step; renewal-likelihood dashboard"integrates with existing PMS"
Colleen Lease AInot statedSMS, email, voice, chat before 90 daysnot statednot statednot statedEntrata (unverified)
AppFolio Realm-Xnot statedResident Messenger renewal messages ("coming soon")rent and term questionsnot stated"Performers" in Flows; a Lease Renewals Flow templatenative
Entrata ELI+not statedoutreach on renewal-intent detectionnot statednative
Yardi Virtuosonot statedchat, email, text, voicefull conversation claimednot statednative
RealPage AI Resident Agentnot statedemail/SMS remindersnot statednot stated"augments human efforts"; "transparency and control for human operators"RealPage
Funnel Resident AI"shares renewal options"expiry notices, options, sign remindersresident Q&Anot statedYardi, RealPage, Entrata
Zuma (Venn, 9/22/2026, ~$50M)not statedrenewal outreach, payment remindersagent "owns" conversationsnot stated"seamless human backup"not stated
Rentify (UAE)not statedrenewal, lease generation, insurance, paymentsnot statedlease generation"approval workflows"not stated
Frontdesk (add-on)negotiates within "guardrails"voice, SMS, email at 90/60/30/15 daysnegotiatesportal or DocuSignguardrails; audit trailYardi, RealPage, Entrata, AppFolio, Buildium
Hyly.AI, BetterBotnot statedrenewal drips and campaignsnot stated
Knock, Buildium, ResMate, LeaseHawk, Lulano native renewal AI found

Sources and the full write-up: scratchpad competitive/renewals-competitors.md (session 1fcfe5de). Published results are vendor marketing (EliseAI's 9% from one case study; AppFolio's 20% from its own survey; HappyCo's +11 points with human support, n≈300, vendor-run).

I. Notifications catalogue: who is told, what goes quiet (code inspection of main a54bb5c3de, 10/12)

RENEWAL NOTIFICATIONS: WHO IS TOLD, AND WHAT GOES QUIET Read-only code inspection of main at a54bb5c3de (2026-10-12 20:36Z). Nothing was run against production. No tenant or customer names below. Paths are under src/lib/ unless they start with agents/, src/app/ or lambda/. Short names: act = temporal/activities/renewal.ts; wf = temporal/workflows/renewal-workflow.ts; bake = domain/escalation/bake-gate.ts; held = domain/escalation/held-text.ts; door = domain/staff-reply/door.ts; batch = domain/leasing/renewal-batch; auto = domain/leasing/renewal-auto-start.ts; notify = domain/leasing/renewal-notify.ts; tools = agents/clara/lib/agent/tools/renewal/handlers.ts; sms = integrations/twilio/client.ts; mail = integrations/email/company-live-gate.ts. Modes: Off / S = Supervised ('drafts') / L = Live. "team" = paperworkSender 'team'. "unverified" = I could not confirm it in code. Merged 2026-10-12 (deploy times unverified): one reviewer email per hold to all reviewers, hello@ BCC (18:17Z); Slack card tags both PropFlow reviewers (16:16Z); plain-note list email (20:33Z, after the 20:26Z event). 10-10: no per-tenant staff page under S (#18548, #18552). "Tell the other reviewers when one decides" (#18998) is an open issue, not built.

THE SHORT ANSWER (why it feels like we send nothing)

  • Under S, staff get one monthly list and nothing else. The list is a snapshot of leases at opening. It never reports what happened afterwards.
  • Approving only signals the workflow. The send happens later. If the send door refuses, the only trace is one log line.
  • Renewals do not use the "Not sent" reporter that tours and prospects use, so a refused approved text reads as approved forever.
  • Many endings are silent by design: out of reminders, resident says no, AppFolio closes it, notice to vacate, list rejected.
  • Several staff emails depend on a setting that can be missing: a chosen reviewer, a renewal contact, an office address, the digest switch.
  • A text the carrier accepts and then fails to deliver is only a field on the renewal page (the email fallback was retired in May). Only a letter sent to a bad number pages anyone.

WHO IS WHO (how staff addresses resolve)

  • PM contact chain = the property's renewalContactEmail, else the property email, else the company escalation-owner email (domain/leasing/pm-contact-email.ts :1-20). Used by rows 12, 13, 16, 19, 24. Executed-lease and holdover notices (rows 17, 18) use a shorter office chain with no company rung: renewalExecutionCcEmails, else renewalContactEmail, else property email (domain/leasing/renewal-execution-notify.ts :120-155). No renewal notice has an org-admin rung: the eight recipient resolvers I read contain none (grep).
  • Reviewers = the company setting heldMessageReviewers['leasing.renewals'] (staff or vendors); empty means nobody is emailed (domain/organizations/held-message-reviewers.ts :29-34; domain/escalation/held-reviewer-email.ts :113-114). Under S the executed-lease, holdover and digest emails are approved by a SEPARATE list, heldMessageReviewers['team.notices'] (domain/escalation/held-card.ts :198; domain/escalation/held-reviewer-email.ts :104-114).
  • PropFlow side = hello@ BCC on the staff emails marked so below; Slack cards in the property's activity channel, else the company front-door channel, else #alerts (bake :185-212).

TABLE 1. WHO IS TOLD (one row per send site)

#TriggerWho is toldChannel / whenOff / S / Lteam paperworkfile:line
1Monthly list of renewals to approveThe company's chosen Renewals reviewers (setting heldMessageReviewers['leasing.renewals'], staff or vendors, each re-checked at mail time): ONE email to all, hello@ BCC. PropFlow Slack card tags both PropFlow reviewers (nobody at sandbox buildings). No reviewer chosen = nobody emailed; the renewal contact only fills the hold's "to" fieldemail, Slack card, page; first daily scan each month; never repeated, never expiresOff, L: no list. S: yesnone (list is per lease)batch/scan-batch.ts :73-79,:100-110,:177-180; batch/open-batch.ts :53-63; domain/organizations/held-message-reviewers.ts :29-34; domain/escalation/held-reviewer-email.ts :113-114,:139-174; bake :506-526; domain/organizations/review-gate-mention.ts :34-42,:74-91
2Reviewer replies "approve" by emailThe replier only: "Thanks, approved ... Everything else goes out as listed" (no hello@ copy). PropFlow's Slack thread gets "Customer reviewer answered". An edit-only reply gets "Recorded ... still waiting for your approval"email; at onceSnonedoor :245-254,:271-272; domain/staff-reply/batch-reply.ts :293-305; domain/staff-reply/answer-reviewer.ts :30-42,:60-92
3Reviewer approves on the pageNobody. The page gets data back and one log line is written. No email, no Slack line (settle-batch.ts has no Slack or email call at all)noneSnonesrc/app/api/admin/escalation-holds/[id]/route.ts :198-226; bake :2625-2630; batch/settle-batch.ts :1-4,:29-76
4Other reviewers told when one decides (#18998)Not built. Only the replier hears (row 2)------door :271-272
5Offer text (Day 0)The resident. Staff learn only through the listSMS; Day 0, pushed past quiet hoursOff: not sent. S: held first (list approved = reviewed body goes out, no second approval; list open = waits; lease not on list = ordinary hold, 24h). L: sentwording changes; no letter legact :826-1160; wf :3580-3610,:3836-3912; domain/leasing/renewal-orchestration/renewal-text-review.ts :70-113; batch/batch-gate.ts :1-90; domain/leasing/renewal-sms-template.ts :26,:55
6Offer email and letterThe resident. Email goes only when there is no phone number (with a phone the email step quietly skips). Letter (picture text) only when the PMS prepares paperworkemail, MMS; Day 0as row 5no letter leg; no PMS prepare wait; "Resend letter" refusedact :1773-1812,:2135-2226; wf :2577-2580,:3102-3108,:3728-3775
7Reminders (48h, +7d) and expiry nudges (60/30/15 days)The residentSMS; per ladderas row 5; a renewal a person owns, or that escalated, is "held" with no sendwording changesact :1296-1398,:1615-1631; wf :3950-4123; domain/leasing/renewal-reminder-sms.ts :105,:140,:235
8Outbound renewal callThe resident (voice)Day 0Off: no call (the door refuses, the workflow is told dispatched_failed, info log). S: no call by default ("calls go to the team"); it dials as Live only if the customer chose "Clara answers calls". L: dials. The workflow throws the result away--act :2728-2731,:2744-2751; domain/leasing/renewal-orchestration/initiate-renewal-call.ts :97-104; integrations/voice/initiate-outbound-call.ts :438-488,:490-521; domain/escalation/supervised-call-state.ts :8-10,:43-50
9Month-to-month warningThe resident by text. The office is paged only if no offer is prepared and the lease is not lapsed; if an offer exists the office is not told it went outSMS (+ email to office); retried every daily scanOff: refused at the door, info log. S: each warning held (never on the list). L: sentrollover never written, so no conversionauto :2518-2954 (:2764,:2925-2945); domain/leasing/renewal-orchestration/mtm-warning-send.ts :141-259; domain/leasing/renewal-holdover.ts :84-90
10Clara's replies, and texts Clara sends mid-chat (offer recap or portal link; the term-change confirmation is row 23)The resident, unless held. S: renewal-topic replies are held; the resident hears nothing except one fixed "Got it, the team is looking at this." if they text again while it waits. Reviewers: PropFlow Slack card only; the customer's staff can find it only by pulling the /review "Held emails" feed. Non-renewal replies sendSMS; on each inboundOff: unverified. S: held. L: sent--domain/modules/supervised-reply-hold.ts :103-131; agents/clara/lib/messaging/process-envelope.ts :466-514,:768-801,:1032-1036; domain/escalation/held-reviewer-email.ts :106-108; domain/escalation/held-reply-ack.ts :4-25; tools :376-399; src/app/api/held-emails/route.ts :29-57; domain/escalation/held-email-rows.ts :26-37
11Resident texts yes or noNo staff message. The workflow is signalled (best effort); a "no" ends the renewal with outcome intent_to_vacate and an audit entry. The event that would page the PM when no live renewal exists has no listener in the text Lambda--S: that page would be swallowed--tools :599-678,:984-1073,:1054-1056; wf :2230-2231; act :4329-4345; domain/automations/handlers/decline-renewal-on-clara-signal.ts :46-116; domain/leasing/renewal-decline-delivery.ts :159-191,:213-282; domain/pms/events/bus.ts :20
12"Needs a person" page for one resident (19 reasons, e.g. counter-offer, said yes but never signed, countersign overdue, offer expired unapproved, prepare failed)PM contact chain: renewalContactEmail, else property email, else company escalation owner; plus a text to renewalContactPhone; hello@ copyemail + SMS; once per lease and reason per 24hS: swallowed for every caller (only reason "unknown" alerts engineering). L: sent--notify :251-300,:327-348,:423-465,:497-501; act :3246-3256,:3298-3300; wf :2257-2258; domain/leasing/renewal-escalation-copy.ts :52-130; domain/leasing/pm-contact-email.ts :1-20
13Held renewal page (opted out everywhere, held for review, no contact details, signer has no email, tenant transferring, no offer price). Also fires when staff click Send offer or Approve; they also get a plain error on screenPM contact chain, as row 12email + SMS; once per lease and reason per 65 daysS: swallowed before the once-slot, info log. L: sent--domain/leasing/page-pm-for-held-renewal.ts :6-14,:103-129,:154-162; src/app/api/leasing/renewals/outreach/route.ts :278-325; src/app/api/leasing/renewals/approve/route.ts :481-509; domain/leasing/renewal-escalation-copy.ts :71-85
14Resident asks for a person or counter-offers (Clara's renewal_escalate)The property's own main email only (not the renewal-contact chain), hello@ copyemail; during the chatOff: refused. S: NOT held (declared "no module", so the Supervised email net is skipped; only the company-live check applies). L: sent. Code-read, runtime unverified--tools :68-91,:444-455,:1075-1082,:1355-1357,:1467-1477; mail :376,:476-515
15Matter and decision request to the escalation ownerThe escalation owner, only when the PROPERTY itself names one; otherwise no matter at allemailHeld when the company review switch (reviewOutboundEmails, needs company live) is on and the property is not autonomous; else emailed--tools :1195-1261; domain/escalation/open-matter.ts :796-872; domain/properties/escalation-bake-gate.ts :1-10,:38-55
16Resident signed, PM must countersign (14-day wait)The PM, email only: the FIRST reminder, and only if the company opted in (default off). Reminders two onward are retired. No text. At day 14 the workflow escalates: PM pageemail; once, then the page at day 14S: page swallowed. L: sent. Off: unverifiedcountersign path under team: unverifiedtemporal/activities/pm-action-reminder.ts :427-476,:517-543,:650-664; wf :1890-1971,:2154-2159; auto :1481-1497
17Lease executed ("renewal done")The office: renewalExecutionCcEmails (first is To), else renewalContactEmail, else property email; signed PDF attached; hello@ BCCemail via Team noticesOff: nothing, counted as handled. S: held; an approval email to the Team notices reviewers (none chosen = PropFlow Slack card only); if it expires unapproved (24h) the drain holds it AGAIN under the same id, and each re-hold writes a fresh pending row, a new Slack card and a new reviewer email (no dedupe found), so reviewers are re-nagged about daily until a person acts; only a person's reject ends it (bake :464-530; domain/escalation/team-notice-send.ts :124-143). L: sent--act :3902-3985; domain/leasing/renewal-execution-notify.ts :129-155,:322-332,:392-436; domain/leasing/send-pending-notice.ts :111-124,:166-175; domain/escalation/team-notice-send.ts :108-143; domain/notifications/observer-copy.ts :66-72
18Lease rolls to month-to-month (holdover)(a) The office gets a heads-up email, same chain as row 17, hello@ BCC. (b) The PM contact chain is paged only if the lease lapsed while held for review ("held lapsed"), as row 13. Nobody else hears of a rollover(a) email via Team notices, next daily scan. (b) email + SMS(a) as row 17 (re-hold after expiry: unverified). (b) S: swallowed; L: sentrollover never written, so (a) never fires (inferred)domain/leasing/renewal-holdover-notify.ts :151-247; auto :1403-1440,:1600-1645
19Leases-ending digest (ending soon, resident never answered)The PM contact chain (renewalContactEmail, else property email, else company escalation-owner email); no hello@ copy. One email per property per business day; nothing on empty or closed daysemail via Team noticesProperty switch renewalLapseDigestEnabled, default OFF. Then Off: nothing. S: held for the Team notices reviewers (re-hold after expiry: unverified). L: sent--domain/leasing/renewal-lapse-digest.ts :1-32,:285-331; auto :625-637,:2385-2417; data/types.ts :17390
20Notice to vacate arrives from the PMSNobody. The renewal stops, the resident is stamped "Notice to Vacate filed", pending reminders just stop. Registered in the AppFolio-sync runtimenone; on syncno Renewals-module check in the handler (grep); one upstream is unverified--domain/automations/handlers/decline-renewal-on-ntv.ts :139-154,:302-336,:406-489,:572-581; domain/automations/registry.ts :12-14; lambda/appfolio-sync/handler.ts :339-340; wf :2092,:2227-2228
21AppFolio shows the renewal finished outside ClaraNobody. Renewal closes "resolved externally"; conflicts go to an audit notenoneno Renewals-module check in the handler (grep); one upstream is unverified--domain/renewals/external-apply.ts :1-84; wf :1487-1518
22Sent / Not sent / Expired / Withdrawn linesPropFlow's Slack thread for the hold only (in the property's activity channel, else the company's front-door channel, else #alerts); never the customer's reviewersSlack; after each eventS--domain/escalation/held-sent-note.ts :97-156; held :466-482,:796-816; act :1225-1235; bake :185-212
23Resident asks for a different term and the AppFolio robot applies itThe resident gets a confirmation ("your renewal is now an N-month term"). Staff are not toldSMS; when the robot reports backOff: refused at the door. S: held (a hold that cannot be written is logged and NOT sent; nothing retries after the 24h expiry). L: sent--src/app/api/leases/[leaseId]/renewal/route.ts :516-523,:931-965,:967-985; data/types.ts :22849-22854
24Renewal letter text bounces for good at the carrier (bad or unreachable number: Twilio 30003, 30005, 30006)PM contact chain, as row 12, told the number on file is wrongemail + SMS; once per lease per 65 daysS: swallowed. L: sent. team: no letter, so never--domain/leasing/renewal-orchestration/letter-mms-status.ts :35,:61-63,:86-134,:185-190; domain/leasing/page-pm-for-held-renewal.ts :103-129
25A renewal call ends with no decision (voicemail, missed, busy, rejected)The resident gets a recap text with the offer and portal link. Staff are not toldSMS; once per call (30-day key)Off: skipped (info log). S: held (a hold that cannot be written is logged and NOT sent). L: sentnot checked (unverified)domain/leasing/renewal-orchestration/recap-sms.ts :104-138,:250-282,:294-325,:385-399
26Engineering alertsPropFlow only (Sentry, #alerts, bake-alert email): stuck-renewal sweep every 15 min; dead-workflow check hourly; lapsed lease with a cycle on file; warning not sent; countersign stalled; prepare-failed retries; AppFolio refused the eligibility read 3 days running (never the PM); SendGrid bouncesSlack, email, Sentryall modes; the stuck sweep has no Supervised awarenesspaperwork_by_team never alertsdomain/renewals/stuck-saga-sweep.ts :121,:145,:193-197; src/app/api/cron/renewal-workflow-health/route.ts :1-114; auto :1182-1215,:1481-1497,:1714-1743; domain/renewals/retry-failed-prepare.ts :1187-1287; src/app/api/sendgrid/event/route.ts :308-332,:503-529; domain/leasing/renewal-read-refused-skip.ts :20-62

TABLE 2. SILENT OUTCOMES (the only result is a log line or an unread field)

#Silent siteResident seesRecord showsStaff / reviewer seesPropFlow seesfile:line
1Opt-out refuses a renewal text (blocked at every opt-out scope; a START to one company reopens only that company; scope defaults to "all")Nothing arrivesWorkflow told dispatched_failed; hold stays "approved"; no undelivered flag; send claim releasedReviewer was told "approved, Clara is sending it now"; the list page still says offers go out; no Not-sent noticeOne warning log linesms :896-905; act :1126-1135; domain/compliance/suppression-gate.ts :217-225,:256-259,:339-366; domain/compliance/suppression-matrix.ts :12-13,:134-136; domain/staff-reply/answer-reviewer.ts :30-42; src/app/(workspace)/admin/escalation-holds/[id]/RenewalBatchView.tsx :155-158
2Root cause of row 1: no opt-out check before the hold is made, and renewals call only the "Sent" half of the reporter that tours and prospects use for "Not sent"SameAn opted-out resident's text is held, listed and approvableLooks normalNothingdomain/leasing/renewal-orchestration/renewal-text-review.ts :70-113; act :1148,:1717,:2083,:2434; temporal/activities/tour.ts :399; domain/escalation/approved-hold-not-sent.ts :1-150
3Opt-out lookup failsNothing (outreach fails closed)dispatched_failedNothingSentry fatal: the one loud casedomain/compliance/suppression-gate.ts :231-239
4Test-scope guard (a sandbox or test building may reach only our own numbers and inboxes)NothingText: dispatched_failed. Email: BLOCKED ledger rowNothingWarning logsms :971-990; mail :337-360; notify :371-381
5Company-live gate (org_not_live): email door only, the text door has noneNo emailBLOCKED ledger row; a transient "hold"NothingInfo logmail :482-514; integrations/email/send-durability.ts :130; agents/clara/lib/messaging/process-envelope.ts :483-487
6Module Off at the door (text, call)NothingText stamped channelOutcomes.sms "held_module_off" (reminders: no stamp). Call: dispatched_failed plus a refusal row; S with the default call choice is refused the same wayNothing (the company's own choice)Info logact :1115-1125,:1615-1621,:2744-2751; sms :1038-1111; integrations/voice/initiate-outbound-call.ts :438-521
7Supervised safety net refuses a send that carries no approvalNothingRefusal rowNothingSentry fatalsms :1114-1160; mail :443-473
8A step skips but tells the workflow "sent": PM pause, robot disarmed, building not enabled, resident already declined, already tried this cycle, quiet-hours backstop (same for reminder, email, letter, call)Nothing, now or laterNothingNothingWarn or info logact :830-880 (quiet hours :873-879),:1296-1352,:1773-1812,:2135-2175,:2539-2620
9Other "not sent" returns: no phone, no offer prepared, no outbound line, approved hold no longer valid, carrier errorNothingWorkflow ignores the result: Day 0 just starts the 24h clock; the nudge ladder is marked done even if it failedNothingWarn log ("no line" also alerts via the resolver)act :886-893,:937-941,:985-990,:1152-1162; wf :3836-3912,:4121
10Renewal email bouncesNo email. The bounce-to-text fallback is built for prospect threads (renewal mail: unverified)Workflow told "failed", used only to block "Resend letter"; ledger corrected; hold's Sent line flipped to Not sentNothing#alerts page (engineering)src/app/api/sendgrid/event/route.ts :308-332,:341-389,:549-575; wf :2317,:2536-2545; bake :2996-3055; agents/clara/lib/email/ndr-bounce.ts :391-621,:666-753
11Held offer, reminder, reply, call recap or term-change confirmation expires at 24h (no workflow waits on the last three, so nothing retries), or a newer draft replaces itNothingHold closed; workflow told dispatched_failed; the older draft is "withdrawn" quietlyS: nothing (the PM page for an expired offer is swallowed). L: PM pagedSlack thread line "expired" or "withdrawn"wf :2452-2470,:4160-4171; held :466-482,:796-816,:824-903; act :1178-1240; data/types.ts :22849-22854
12List rejected or lease struck: every parked hold closed "rejected"NothingWorkflow ends with "no page, our reviewer already knows"Nothing beyond their own reject. The workflow's comment assumes PropFlow's own Slack reviewer rejected (wf :4176-4180); a customer reviewer who rejects is told nothing more (inferred)Nothingbatch/settle-batch.ts :62-64; batch/batch-gate.ts :75-89; wf :4172-4182
13Lease not on the list (appeared after it opened, or its pointer is unreadable): falls to an ordinary per-send holdNothing unless someone approves within 24hHold, expires as row 11No email, no list lineSlack card only (no mention at sandbox buildings)batch/batch-gate.ts :23-39; batch/scan-batch.ts :100-110; domain/escalation/held-reviewer-email.ts :106-108
14List never approvedNo offers, reminders or nudgesHolds stay parked; workflow rechecks every 24h; the list never expiresNo reminder to reviewersSlack bumps at 1h and 3h only; the stuck sweep skips OFFER_PREPAREDwf :2451-2456; bake :3261-3272,:3297,:3320-3326; held :1173-1184; domain/renewals/stuck-saga-sweep.ts :193-197
15No Renewals reviewer chosen for the company (a company with no Team notices reviewer parks the executed-lease, holdover and digest emails the same way)No offers (all parked)List exists on a pageNobody emailed; no one on the customer side is pointed at itSlack card onlydomain/escalation/held-reviewer-email.ts :113-114; bake :524-526; domain/escalation/team-notice-send.ts :140-162
16Approval cannot be applied (pointer flip fails, or one release fails)Offers stay parkedPage says approved; workflows still parkedPage says approvedSentry exception (logError)batch/settle-batch.ts :34-37,:69-71; platform/logging.ts :129-148
17Under S every per-tenant staff page is swallowed: expired offer, counter-offer, said-yes-never-signed, countersign stall, held renewal, bad-number letter, undeliverable decline, prepare failed (PM-fixable)n/a"supervised: no per-tenant page"; once-slot releasedNothing; the list covers only leases on it, as of openingOnly reason "unknown" alerts engineering; the stuck sweep waits 72hnotify :233-300; act :3298-3300; domain/leasing/page-pm-for-held-renewal.ts :103-120; domain/leasing/renewal-decline-delivery.ts :254-282; domain/renewals/stuck-saga-sweep.ts :145
18Workflow ends quietly: outreach exhausted, lease gone, wrap-up (AppFolio close-out or PM-decided month-to-month), countersign wait endsn/aAudit-only "outreach_exhausted"; no outcome noticeNothingNothingwf :1487-1518,:1627-1648,:2154-2159,:4006,:4120,:4235
19A step throws or a signal failsNothingA thrown send becomes dispatched_failed; approve-signal failure flags undelivered with a Not-sent line; reject-signal failure is log onlyNothingWarn log; dead workflows caught hourly (engineering)wf :3819-3835; held :729-733,:780-782; act :2395-2513; src/app/api/cron/renewal-workflow-health/route.ts :1-114
20Clara's own text tool reports "sent" even when the door refusedNothing, though Clara may say she textedTool result sent:trueNothingDoor warningtools :401-423,:1558
21Executed-lease, holdover or digest email has no address, or does not deliver; or the digest switch is off--No address: unmarked, retried every tick, no alert. Not delivered: logError. Switch off: info "went unreported"Staff never learn the lease signed, rolled, or is endingSentry only on not-delivereddomain/leasing/renewal-execution-notify.ts :301-307,:425-433; domain/leasing/renewal-holdover-notify.ts :155-161,:214-224; domain/leasing/renewal-lapse-digest.ts :285-294,:335-347; auto :2385-2394
22Month-to-month warning refused (no phone, opt-out, quiet hours, no line, person owns it)No warningNo receipt, retried each scan; conversion blocked while unwarnedNothingOne engineering alert, only if the lapsed lease has a cycle on fileauto :1178-1183,:1714-1719,:2518-2721
23Clara's loop returns an empty replyNo replyLog "No outbound ... empty reply"NothingLogagents/clara/lib/messaging/process-envelope.ts :646-658
24Offer or reminder text accepted by the carrier, then fails or is undeliveredA late or missing textLease field channelOutcomes.sms = sent_undelivered or sent_failed (shown on the renewal page). The log says the email fallback is "retired" and the reminder ladder "will retry" (to the same phone). The status route's comment still claims an email fallback firesNothing. Only a letter to a bad number pages anyone (Table 1 row 24)Info logact :752-791,:1136,:1633; domain/leasing/renewal-orchestration/sms-cascade.ts :1-20,:112-121; src/app/api/twilio/status/route.ts :101-116
25Letter text blocked by a carrier filter (30004, 30007, 30032, 30034), or its text leg is refused so the picture leg is skipped, or only the picture failsNothing, or the words without the PDFletterMms outcome and detail stamped on the lease: a pull-only line, no push (only the bad-number codes page)NothingInfo logdomain/leasing/renewal-orchestration/letter-mms-status.ts :36,:46-48,:176-190; domain/leasing/renewal-orchestration/send-renewal-letter-mms.ts :295-326,:380-411
26After-call recap text skipped: no phone, no tenant or building on the call, already done for this call, no offer rent on the call, or no outbound lineNo recapNothing; the per-call key is already used, so no second tryNothingInfo log (a missing line also alerts through the resolver)domain/leasing/renewal-orchestration/recap-sms.ts :109-138,:199-202,:223-235
27After-call recap text refused at the door (opt-out, test building) but recorded as sentNothingAn activity entry "Sent SMS recap to ..." and an info line are written without checking the door's answer (no message id comes back). Code-read; not seen at runtimeNothingInfo logdomain/leasing/renewal-orchestration/recap-sms.ts :294-325,:385-399
28Term-change confirmation cannot be sent: no tenant, no phone, no outbound line, or the door refusesClara promised a confirmation; none arrivesWarning or info log only; the term change itself is already savedNothingWarn or info logsrc/app/api/leases/[leaseId]/renewal/route.ts :510-515,:843-880,:995-1001
29AppFolio refused or timed out the eligibility read for a leaseThe renewal does not start that dayA "read unavailable" marker; every daily scan retries; never a PM page, never the 65-day once-slotNothingONE engineering alert (email and fatal log) after 3 days in a rowdomain/leasing/renewal-read-refused-skip.ts :1-9,:20-62

THE THREE EVENTS FROM TODAY

  • 20:26Z opt-out block (per the brief; the code chain is verified, the log was not re-read): approval only signals the workflow (held :720-728). The workflow re-ran the send (wf :2484-2510). The text door refused it as opted out (sms :896-905). The step logged a warning and returned dispatched_failed (act :1126-1135). Renewals never call the Not-sent reporter (Table 2 rows 1-2), so no flag, no Slack line, no email, and the hold still reads approved. The resident was correctly not texted; the reviewer was never told. It could happen because nothing checks opt-out before the hold exists (domain/leasing/renewal-orchestration/renewal-text-review.ts :70-113).
  • 20:42Z held reply, Slack only: the sandbox resident said they plan to renew. Under S a renewal-topic reply is held (agents/clara/lib/messaging/process-envelope.ts :768-801). Renewals holds send no reviewer email (domain/escalation/held-reviewer-email.ts :106-108). The Slack card at a sandbox building carries NO @-mention (domain/organizations/review-gate-mention.ts :34-42,:74-91), so it pinged nobody. The resident hears nothing by design (agents/clara/lib/messaging/process-envelope.ts :771-773).
  • 20:50Z "second held reply": my reading of the saved CloudWatch extract differs from the brief. A sandbox resident texted that they changed their mind and are moving out. The decline tool ran (intent recorded, no staff email), the follow-up event found no listener in the text Lambda, then the loop returned an empty reply (agents/clara/lib/messaging/process-envelope.ts :646-658). There is no "Review mode: withholding" line (agents/clara/lib/agent/conversation-manager.ts :16764-16771), so this was NOT a hold: nothing was held and nothing was sent. Why the reply was empty: unverified (another agent is investigating).

3. THE REVIEWER'S VIEW AFTER THEY APPROVE THE LIST

  • By page: a fixed banner, "Approved. Clara sends the listed offers now; lines marked not renewing stay out." Nothing is emailed (src/app/(workspace)/admin/escalation-holds/[id]/RenewalBatchView.tsx :155-158; src/app/api/admin/escalation-holds/[id]/route.ts :198-226).
  • By email: one reply, "Thanks, approved ... Everything else goes out as listed." Other reviewers get nothing (domain/staff-reply/batch-reply.ts :302-305; #18998 open).
  • Afterwards: nothing. The status column says Going out, Not renewing, or Held: reason. No sent, blocked or replied field exists (batch/batch-lines.ts :14-27; src/app/(workspace)/admin/escalation-holds/[id]/RenewalBatchView.tsx :118-130).
  • Sent and Not-sent lines exist, but only in PropFlow's Slack thread (domain/escalation/held-sent-note.ts :97-156).
  • No "since last list" summary exists: only the list builder, the email renderer and the page read the list members (grep).
  • A lease that appears after the list opened is never shown to the reviewer (Table 2 row 13). The next list opens on the first scan of next month.
  • Under S no per-tenant page reaches staff for replies, declines, bounces, opt-outs or expired holds. They can only pull the /review "Held emails" feed (pending items only; approved ones drop out of it).

UNVERIFIED

  • Deploy times of the three 10-12 changes, and whether the 20:26Z, 20:42Z and 20:50Z events ran on them.
  • Why the 20:50Z reply was empty.
  • Whether renewal_escalate's PM email really goes out under S at runtime (code says yes), and whether Off blocks the decline, notice-to-vacate and AppFolio close-out paths (those handler files contain no Renewals-module check; a check upstream of them is unverified).
  • Whether bounce handling reaches renewal offer emails sent outside held review, and whether a bounce texts the resident.
  • The countersign path under team paperwork; which hold kinds the /review feed shows a customer reviewer; whether Clara's reactive renewal replies still go out when Renewals is Off (a code comment suggests yes); whether the recap text is worded for team paperwork.
  • Staff routes under src/app/api/leasing/renewals and renewal-change-reviews were scanned for send calls: they signal or start the workflow, and only approve and outreach page the PM (row 13). The change-review approval and the cohort walker were not read in full.
  • logError records a Sentry exception; logCritical is the high-priority page. I did not check Sentry alert rules.
J. How the design evolved, March to October 2026 (raw transcripts, docs, ADRs, PRs; quotes machine-checked)

Read-only history for tonight's design doc. Every quote was machine-checked against the source text (dictation garbles left as spoken; tenant names and phone numbers removed). Bold rows are turning points.

Coverage: team-meeting transcripts in Slack reach back to 2026-04-26 (Slack access worked). Fede's own typed words on renewals in his sessions start 2026-08-31. Earlier design comes from docs, ADRs and PRs. Fede's last session note is a design doc still in progress.

Mar-Apr   May-Jun        Jul-Aug          Sept            Oct 1-12
BUILD  -> POLICY AT   -> TRUST: only say -> ONE ENGINE,   -> CENTRALIZED CUSTOMER:
screen,   CAMELLIA,      what AppFolio     month-to-month   Supervised, paperwork
robot     autonomy on    confirms          is the end       split, reviewer list,
                                           state; WS joins  then "levels"

How the thinking moved

Renewals began in March as a screen plus automatic texts, and by April a browser robot created the offer inside the customer's own AppFolio. At Camellia the intent was prepare and send, with people only for exceptions, and by July 'its already on'. The summer was about trust: say only what AppFolio confirms, let AppFolio win any disagreement, and fall back to month-to-month. In September two renewal engines became one (9/3), and on 9/5 Fede ruled that a tenant who stays on month-to-month is not re-offered. Western Slope then arrived with a different shape: a central manager who renews by hand, wanted a stoppable heads-up, and was pitched "autonomous within policy". The design went further than they asked: hold every message until approved, a monthly reviewer list, and a setting for who sends the paperwork. On 10/12 Fede called these layers 'too complex' and recast them as levels of autonomy: Supervised is a one-week soak, and Camellia is the top level.

Timeline

Era 1: Build (March to April)

DateSourceWhat was decided or saidWhat it changed
2026-03-09git log, via one-doc historyFirst commit naming renewals: Renewals tab Phase 1. By 3/17 it adds auto-outreach and a manual Send Outreach button for demos.Renewals starts as a screen plus automatic outreach, built for demos, before it is a workflow.
2026-04-12PR #62First auto-send: "Auto-send for good-standing tenants — renewalAutoSend setting (OFF by default, safe for prod)".Offers can go out with no manager click, for good-standing tenants only.
2026-04-16memory ruling, via one-doc registerFede authorizes autonomous-renewal testing at the Willows test property only: "prepare AND send with no pre-ask". More than one month of rent owed means a person reviews.First statement of intent: Clara acts without asking. First (loosest) balance rule.
2026-04-22PR #366; memory rulingsThe guard that blocked writing to Camellia's AppFolio is removed. Fede: "DO NOT USE THE NATIVE LEASE TEMPLATE. KEEP CAMELLIA TEMPLATE." and "ALL TERMS MUST BE CREATED… never guess or pick… exactly what the policy says."Clara's robot creates and sends the offer inside the customer's own AppFolio with the policy's exact terms. This is the "Clara sends the paperwork" path.
2026-04-26founders, dashboard redesign (transcript)Sean's first spec of what a manager should see: "How many of those have renewed? How many of those are waiting a response? And what's my renewal percentage for the month?"Renewals are measured as a funnel for the asset manager before the automation exists.

Era 2: Policy invented at Camellia, autonomy on (May to June)

DateSourceWhat was decided or saidWhat it changed
2026-05-02founders, Denver whiteboard (transcript)Fede's first end-to-end picture: "We call them to explain the terms, we text them the renewal letter. And then they can just log into their portfolio. And sign in." (The transcript says portfolio; he means the resident portal.)The original vision: Clara calls and texts, the tenant signs online, no staff step.
2026-05-07founders, renewals demo (transcript)Early renewals are supervised. Sean: "if it says review, it means, like, that that's ready for the manager to review and send." Same day he asks: "If we send the renewal offer and they don't respond to it, what's our follow-up? Like, 48 hours?"A manager reviews and sends each offer at first. The first reminder is set at 48 hours.
2026-05-11docs/autonomous-renewals/policy.mdThe first written design, for Camellia: "Renewals were paper-based until Clara turned on (~April 2026)." It proposes a daily job scoring each tenant on a ten-gate scorecard.The original paper design. The build is reverted a day later (5/12).
2026-05-12PR #881The overnight policy build is reverted whole. Reasons: simplify step skipped, bot review missed a bug, internal jargon shown to owners.The policy engine stays small. A process lesson, not a design reversal.
2026-05-19founders standup (transcript)Fede's escalation rule: "When someone doesn't answer a renewal for a week, then I escalate to human."Silence for a week goes to a person. Later reversed twice (7/17 quiet wrap-up, 8/13 never give up).
2026-05-20founders standup (transcript)On renewals that involve collections or eviction, Fede: "I would say at least 50% of renewals in Camellia are like that. We're like, we probably won't be able to automatically."The expectation in May: about half need a person. By 7/13 he reports about 90% going out on their own.
2026-05-21memory ruling, via one-doc registerCamellia's property manager gives the rules: balance, not lateness, is the disqualifier; more than 2 months owed goes to a person; her preferred hand-off channel is SMS, not email.First customer-given policy. The owed-rent line moves from 1 month to 2 months.
2026-05-22PR #1307Eligibility "v6": two checks (months owed, late payments) and only two results, AUTO_RENEW or HITL_REVIEW, with no score. A five-gate scoring prototype is dropped.Eligibility becomes auto or a person.
2026-05-24ADR-0025 update; PR #1376Renewal timers and retries moved to Temporal Cloud on 5/14. On 5/24 the old send switches are retired: one fail-closed gate, a text needs the global arm and the property flag, and ships disarmed.Every send fails closed.
2026-06-03ADR-0046 (decided on the JP/Camellia accounting call)A lease that lapses unsigned converts to month-to-month at the property's premium, the office is emailed on every signed renewal, and the reminder warns about the roll. Register: "Holdover is fully autonomous".Month-to-month becomes the built-in fallback. The first office notifications exist because accounting asked.
2026-06-03accounting-gaps call, Camellia and JP (transcript)Origin of the month-to-month fallback. Sean: "if they haven't signed it, but the lease expires, then Clara will go in and change it to month-to-month in AppFolio." Fede adds that the tenant should be told: "now you're month to month."An unsigned offer at lease end rolls to month-to-month, and the tenant is told. Written up the same day as ADR-0046.
2026-06-03accounting-gaps call (transcript)Why accounting wanted it. Fede: "people were signing renewals after they expire already. […] your lease expires, and then it's like, oh, 15 days later, you sign." A double charge the month after a renewal had surfaced the day before (6/2).The fallback fixes leases signed after they expired and the double charges that followed.
2026-06-04ADR-0047The 6/2 plan to delete the saga is overruled: "The RenewalSaga DynamoDB entity is retained as the durable identity, audit, and read-model anchor for a single renewal cycle."One stored record per renewal cycle stays; the workflow writes it.
2026-06-08prod-learnings standup (transcript)After a small test send with one unclear reply, Fede: "what I'm gonna do is, after this call, I'm gonna turn on the autonomous renewal, so I don't have to approve them anymore. They're just. start going out by themselves." Rule stated: under one month outstanding sends; above it, "it's flagged for human review".Manager approval ends in Fede's plan. The 6/22 ADR notes Camellia was still holdover-only then, so autonomous offers began later.
2026-06-09memory rulings, via one-doc registerAn emailed notice to vacate is valid: "Do NOT re-argue the 'is email legally valid notice' angle — Fede decided it is." Also no manual comms outside the pipeline.Notice by email counts as notice.
2026-06-16founders standup (transcript)Fede on Camellia's office: "Renewals are fully automated. All they have to do is click one button to sign. Before, they took three hours by paper. […] it takes them, like, two, three days to click one button."The slow step is the office's countersign, not Clara. It drives the 7/22 reminders.
2026-06-22memory ruling, via one-doc register"Do NOT add a legal/eviction gate to the decision engine. Legal signals are too flaky; late-payment count is the deliberate proxy."Eligibility stays simple. Revisited 7/20.
2026-06-23ADR-0066 option C (Fede); PR #2573The eligibility verdict now gates the text: "Fails closed — a missing verdict holds, never sends blind." On Camellia's live group, read-only, 11 would-be sends to people who need a person fell to 0.A text goes out only when the rulebook says auto.

Era 3: Trust and AppFolio wins (July to August)

DateSourceWhat was decided or saidWhat it changed
2026-07-07memory ruling (PR #3257)"Just have it on", "no more flags": the retry switch is deleted and retry becomes unconditional.Early form of the later rule that fixes never get a switch.
2026-07-07founder chatFede ahead of the Camellia session: renewals "need to start asking them to review the ones that are not auto sent because of payment history".First sign of a customer reviewing the renewals Clara holds back.
2026-07-08founders with Camellia staff (transcript)Gera asks Camellia's Joanna the "who sends" question: "Would you want it, Joanna, to go to you, where maybe you send it, um, or you confirm it, and then it would send, or do you want us to just send it on your behalf?" No answer in the transcript.The send-or-confirm choice is put to a customer for the first time. It returns for Western Slope on 10/8.
2026-07-15ADR-0091"Treat the PMS as the system of record for tenancy facts (lease terms, offer status, charge schedules, scheduled increases, move-outs)." The first version has a manager confirm any conflict.Start of the rule that AppFolio wins.
2026-07-16walkthrough with Camellia staff (transcript)What a flag means. Sean: "it's not gonna send out the renewal until you review it and approve it." Joanna gives her own rule: "if they owe, like, 2 months or more, they're getting sent a 10-day, and they're not being offered a renewal".At Camellia, held renewals wait for the office's approval. The two-month line is the customer's own.
2026-07-16walkthrough with Camellia staff (transcript)Kenya on countersigning: "I think we were saying to countersign within 72 hours". Fede describes Clara's cadence: a monthly text, then "if you don't renew, we're going to move you to month to month. […] And that has a $100 premium."A 72-hour promise by the office. The monthly reminder plus month-to-month warning is described to the customer.
2026-07-17PR #3985 (ADR-0091 addendum)When AppFolio shows a renewal handled, the workflow wraps itself up: "No contradiction → no human at all." The body calls it founder-ratified: less clicks, less reviews.The manager-confirm step is cut (finished on 9/3).
2026-07-17PR #4020 (ADR-0100)A fourth way a renewal ends: "the PM decides not to offer a renewal and lets the tenancy continue month-to-month." "No tenant comms anywhere."A manager can roll a lease with no offer and no message.
2026-07-22ADR-0108 (PRs #4322, #4374)One decision spine: the daily scan, the staff buttons and the watchers all run the same gate pipeline. Thirteen fixes land that day.One rulebook for who may be contacted.
2026-07-23memory ruling, via one-doc register"its already on": autonomous renewals at Camellia are on by intent. Policy v2 is locked at 2 months owed, 6 late payments, 25 days of grace; a dry run moved auto-approval from 59.3% to 92.0%.Camellia is the live, autonomous reference customer.
2026-08-03founders standup (transcript)How outreach felt in early August. Fede: "Just the renewal engagement is pretty low. […] someone says you're a scammer. […] Because it is a random 800 number." On 8/6 he describes the order: "We call them, leave a voicemail, then text them a renewal offer letter."Calls and a toll-free number get little trust. This leads to text first, no opening call (9/28).
2026-08-06Camellia standup (transcript)Fede after a tenant asked for a new-tenant special: "there should be a renewal policy now. Anyone that asks, we should say, hey, this is for new movies only. The AI should learn that." Sean: "it's for new move-ins only. No, not renewals."A rule from the customer becomes a policy Clara follows.
2026-08-13founder voice memoAutonomy as a principle: "remove work away from the human as much as possible escalate as little as possible when we escalate we create a policy and learn and the next time we don't".Each escalation should become a saved policy. Echoed 8/18 and again on 10/3 (company brain).
2026-08-13Camellia call (transcript)A real counter-offer, read out by Sean: "A thousand is currently being advertised on the Camellia website for new tenants leasing studio floor plans similar to mine. If possible. I greatly appreciate if a comparable rate could be considered for my renewal." Camellia's staff also note Spanish-speaking tenants "came down, they were like, who is Clara".Clara does not negotiate; it goes to the office. The 8/3 findings page confirms "never negotiate" held.
2026-08-18founder voice memoFede on approvals: "i just don't think like having a dashboard where they go review conversations and approve things that i just don't think that will ever happen". Instead, staff replies become policy: "what's a one-off exception versus like a general policy".Approval moves off dashboards to email and text. The 10/8 to 10/12 reviewer list comes back to a page as a backup.
2026-08-25Situs demo (transcript)Situs's Eileen: "if you're calling and texting them, and it's not going back through the API to be captured by AppFolio." The 'Hugo' label (it covers more than one voice) adds: "How do we hone in on the unknown still, where, like, they haven't made a decision?"Customers want every renewal contact written back to AppFolio, and a plan for the undecided.
2026-08-25Situs demo (transcript)A fear and the answer (labels mixed). "If we fat finger a renewal rate on our, you know, market rent […] catastrophic problem." Reply: "there's a process where you first start with a human in the loop reviewing everything. We don't start going autonomous where it just sends out stuff."Human-in-the-loop first for a new customer. The 8/26 follow-up draft: "Our philosophy is to earn autonomy rather than turn everything on at once."
2026-08-31Fede session a566db0cAfter a delinquent tenant was sent a holdover reminder: "i originally wnated the holdover to be attached to the renewal workflow not standalone" and "i dont want a standalone rogue process".Holdover must live inside the one renewal workflow. Starts the "one engine" thread.

Era 4: One engine, Western Slope arrives (September)

DateSourceWhat was decided or saidWhat it changed
2026-09-02Fede session 28bc997eOn a built-but-gated behavior: "this should always be on, remove the feature flag andd deploy".Early form of the no-switch-on-live-behavior rule.
2026-09-02standup (transcript)Fede's onboarding idea: "hey, do you want to send autonomous renewals out, or do you want, like, someone to check it first? […] after, like, a month of checking it, you, like, say, okay, I'm good to go."First statement of check-first, then autonomous, as a customer's choice. The generic gate is covered elsewhere.
2026-09-03architecture page; PR #6902Two starters ran Camellia renewals at once (11 cases, 5 a month early, PM pages sent twice). Fede picks "one starter, one owner, fix in place." The second starter is deleted because "a switched-off-but-present starter is exactly the kind of thing that gets accidentally re-armed."One daily scan is the only thing that starts a renewal.
2026-09-03architecture page (cadence ruling, dated 08-31 there)Reminder cadence: "reminder 3 times like we do today with leases. business days only. once per day max."Three reminders, business days, once a day. Not applied to every case (see tensions).
2026-09-03memory rulingWhen AppFolio already shows a renewal handled: "this is wrong. if it was updated in appfolio we should just follow the signal, no one is going to manually review."Clara follows the property system's own signal. No confirm queue.
2026-09-03Fede session 28bc997eSeeing 5 renewals started a month early: "i dont undertadn why there are 2 engines" and "i never approved or revieewed any new architecture". Then: "i want to never worry about this again".The two-engine decision. One engine, finish the migration (Option B, merged that day).
2026-09-03Fede session 28bc997eWhen the system saw AppFolio already updated: "if it was updated in appfolio we should just follow the signal, no one is going tmanually review".AppFolio facts are followed, never confirmed by a person.
2026-09-03Fede session 28bc997eOn the call that refused to talk about a renewal because a name did not match: "we should just say the offer" and "remove the rule and add evals".Outbound renewal calls drop the identity gate.
2026-09-04PR #7101Two Camellia leases that ended 8/31 were skipped until 9/4 because "our own unanswered offer blocked the month-to-month fallback that exists to clean up unanswered offers." Accepted-but-unsigned tenants are never rolled.The roll-over now runs for unanswered offers.
2026-09-04Fede session 28bc997eOn a missed notice to vacate: "dont we have an automation to set NTV on appfolio when someone submits notice?" and "everything shoud be automatic".Notice to vacate is set in AppFolio with no human step.
2026-09-04Fede session 28bc997eOn the lease-expiry notice to the office: "we want to reduce noise in the mailbox, but i think we could group together and give a headsup to the PM of this a day before they exprire (business day)".Grouped heads-up instead of per-tenant pages. Reappears 10/10 as "i said no per tenant emails".
2026-09-04Fede's chat thread, voice note (speaker unlabeled)Fede's retro: "I feel like I've regressed in a lot of areas of the product, adding all this complexity, guards, warehousing, […] that is kind of collapsing and made things worse. So I'm thinking we're going to go back to basics. And remove everything and go all autonomous again for Camellia."Camellia goes back to fully autonomous; the added guards come out. The same day Option B is chosen (see 9/3 and 9/5).
2026-09-04Fede's chat threadWhy Camellia: "we already know all the policies, we're in the weeds, so we don't really need to be asking [Joanna] anything. And besides, she's not going to answer anyways." The fancier checks move to Situs: "people like [Eileen], she's going to be super engaged". Gera agrees: "it's better to say something than to keep tacking onto this giant queue that we've been building on human review".Review only makes sense where the reviewer answers. Camellia's office does not; Situs's and Western Slope's must.
2026-09-04Western Slope demo (transcript)What Western Slope was told and assumed. Sean: "we like to reach out, like, 90 days before the lease is expiring, and we give them a renewal offer. […] they accept, and then we… we send the, um, the paperwork automatically." Jay: Clara will "send renewals out in the renewal module".The original promise: Clara sends the paperwork itself inside AppFolio. Western Slope does not renew that way (9/9).
2026-09-05ADR-0046 banner; PR #7137After three Camellia leases roll to month-to-month, Fede: "i dont want to offer anything, just roll mtm." The re-offer code is deleted.Month-to-month is the end state. No second offer.
2026-09-05memory ruling"Silence is not approval." A behaviour fix ships behind a per-property gate, off by default; an unanswered decision is a hold.One of the three rolled units had a human case open.
2026-09-07founder chatFede's pull of Western Slope's AppFolio: "Renewals. Flat. Eight of twelve renewed at the same rent. Where rent moved, the median increase was 2.1%."Western Slope's real pattern is flat rent, which later shapes the first-list rent rule (D6).
2026-09-09Western Slope onboarding (transcript)Jay: "we also use the leasing function for our renewals, as opposed to the renewals function, right? So we're utilizing a handful of amendments in the leasing function". Fede: "if we're consistent and you guys have, like, one process for your whole portfolio, and, like, maybe one template, like, one addendum, you know, those kinds of things simplify."Western Slope does not use AppFolio's renewal tool. The paperwork path built for Camellia does not fit them.
2026-09-09Western Slope onboarding (transcript)Order of rollout. Jay: "if we're going to focus leasing and then renewals and then maintenance, I think that's fine. […] I mean, renewals is gonna be a big piece". Sean on 9/4 had said maintenance, then leasing, then renewals.The customer's order wins for now. On 10/1 Fede runs renewals first for revenue.
2026-09-17Camellia standup (transcript)Of 5 renewals due: "3 did not renew, 1 transferred, and 1 is… we just don't have their contact info". Joanna on one resident: "I don't think we should offer them right now, anyway." Kenya asks for a 'transferred' outcome "so it shows that they stayed".Camellia's staff set exceptions by hand and want transfers counted as stays.
2026-09-18Denver-portfolio call (transcript)Sean's phased plan: "we'll start with the leasing, and then when you guys are ready, we can turn on maintenance, and then when it's ready, we can turn on renewal."Renewals planned last at a second centralized customer.
2026-09-23one-doc, Goal sectionTarget: "Western Slope live on renewals by Friday 2026-10-02, and invoiced for them." Design that day: "Kat inspects that list before anything goes out", Clara sends the texts, replies wait in Slack.First design for a centralized team. Origin of the reviewer list.
2026-09-23team meeting (transcript)Fede on the swap: "the Maintenance phone line, like, they already have that contract till next year." Then: "Yeah, I think renewals make sense." On why he takes it: "renewals, I feel like, needs a lot of fine-tuning."Renewals moves ahead of maintenance for Western Slope, and Fede takes it on himself.
2026-09-28one-doc"The channel is decided: text first, no opening call." 29 calls reached 2 residents and produced 0 decisions. Smallest turn-on is 8 steps, starting with a company-level renewal policy.Voice stops being the opener. Policy moves up to the company.
2026-09-28PR #12897 (dark)One company renewal policy that every property inherits, nearest wins. Why: "A company with no per-property policy (e.g. a newly onboarded portfolio of single-family homes) opens zero renewals, because every property would need its own policy typed in."Policy moves from per building to per company, which a centralized team needs.
2026-09-28founder chatFede on new modules: "we turn on a module and then for a week or a few days we're still reviewing every reply so that's what i did with leasing". Also: "a few days of like sanity check before we turn on autonomous".Review-first for any newly enabled module. Seed of Supervised.
2026-09-29founder chatFede's audit of how Western Slope renews today: "a person decides the new rent by hand. AppFolio's automatic increase is set to $0 everywhere." Offers are "almost always a single 12-month option" and go "about 53 days before the lease ends".The real baseline: hand-set rent, one 12-month offer, late. Opposite of Camellia's engine-set terms.
2026-09-30Western Slope check-in (transcript)Jay on judgment calls: "there's certain tenants that have bad payment history that we just want to go month-to-month with, we don't want to lock them in." And on non-renewals: "We need to schedule a move out in that folio".The customer wants month-to-month as a tool and move-out scheduling automated.
2026-09-30Western Slope check-in (transcript)Sean's pitch: "Clara will just send out the renewals based on those policies. And then if anyone is outside of those policies […] it'll just email you guys and say, Hey, this tenant asked for this." Fede adds: "we send the contract out autonomously".Pitched as autonomous within policy, with exceptions to staff. Seven days later the customer is placed on Supervised.
2026-09-30Western Slope check-in (transcript)Sean on holds: "if they're more than 60 days past due, we're not gonna… we're gonna hold it for review."Hold rules were first pitched as a rule on balance. Jay later said balance above zero (10/7).
2026-09-30Western Slope check-in (transcript)Fede offers review-first: "instead of just sending it autonomously, we review it on Slack, click approve, send it." Gera: "we probably want to be, like, within the hour to two hours." Fede: "it's not, like, urgent. You know, you have three months".A Slack approve step is floated. Renewals are slow enough to wait, so the reviewer list was possible.

Era 5: Supervised, paperwork split, levels (October 1 to 12)

DateSourceWhat was decided or saidWhat it changed
2026-10-01Western Slope go-live page (D1 to D4)Fede confirms week-one placeholders: offer 90 days before lease end; a habitual late payer is held for a person; same rent; Cheryl gets questions and counter-offers.First concrete Western Slope settings, pending their answers.
2026-10-01PRs #14897, #14899Supervised holds renewal texts at the resident's building. "a reply that cannot be held is escalated with its words, never sent live, never silently dropped".The renewal side of the Supervised gate. Held, not sent.
2026-10-03Western Slope go-live page, 10/3 planTurn-on planned for Monday 10/5. Known risk: "AppFolio emails the tenant the moment an offer is created. Supervised mode holds Clara's texts, not that email, so the Sunday list is the real gate."The risk that drives the paperwork split a week later.
2026-10-07PR #17243"One gatekeeper, one path (Gera, 2026-10-06)." The 9/28 company switch that held renewal texts is removed; 0 of 11 companies had it on.Supervised becomes the one text gate for renewals.
2026-10-07Western Slope questionnaire call (transcript)What Sean tells the customer: "we will send a renewal offer to a tenant, and we'll follow up with them, uh, continuously until they respond." And: "If they don't reply by the expiration date, it just converts to month-to-month."The cadence and the roll-over are explained to the customer.
2026-10-07Western Slope questionnaire call (transcript)Jay on timing and terms: "Clara opens each renewal 90 days before lease ends, yes. We offer a 12-month". On rent, Sean proposes: "we would just bring it up to market" using their spreadsheet.The first customer-given renewal policy at Western Slope.
2026-10-07Western Slope questionnaire call (transcript)Jay on who is held: "I want to renew people at zero". Payment history does not matter if the balance is zero.Eligibility at Western Slope is the balance, not late payments. Camellia's late-payment limit is switched off for Western Slope.
2026-10-07Western Slope questionnaire call (transcript)The customer's ask for control: Clara flags before each 90-day trigger, "and then if we haven't… […] If we haven't, you know, redirected her or told her no, then she goes ahead." Escalations: "Clara will build an agenda, we'll review the items she has escalated in our, you know, our weekly or monthly renewal meeting".The customer asks for a heads-up it can stop, plus a meeting agenda.
2026-10-07Western Slope questionnaire call (transcript)Scope: "I think right now, Clara, building the templates is out of scope. […] the one page renewal could be in scope." Manual for now: "that's Lincoln and Courtyard Apartments." Questions go to "Kat, and she'll escalate to me if she needs to."Lease templates stay with the customer. Two affordable-housing buildings stay out.
2026-10-07internal call on rollout order (transcript)Origin of the split. Fede: "the basic thing that we can turn on now to get. […] Started. Not the fully autonomous, fully fancy version." "Step one could be not even send the contract, just send the communication. […] Because half of their properties don't have a template."Communication and paperwork become separate steps.
2026-10-07internal call on rollout order (transcript)Fede first proposes the customer's heads-up: "Send in a list. […] Of people that we're gonna renew, and if we don't hear otherwise, we'll just… […] Send it out." Gera: "we definitely would want to have some sort of supervised mode right now. Like, we wouldn't want to just send it out to tenants and be like, oh, good luck."Same day, the proceed-unless-stopped list is replaced by hold-until-approved.
2026-10-07internal call on rollout order (transcript)Fede admits what is missing: "if they reply, oh, no, don't do it, like we would need to build that. […] We haven't built that." Instead: "these are the renewals, review them. […] Should we just link to, like, a review page?" Sean on default rent: "a flat or a 25".The reviewer email with a review page is chosen because reply-by-email is not built.
2026-10-08PRs #18017, #18039, #18040, #18041, #18058New setting for who sends the paperwork: "this is a NEW capability setting. The default is 'clara', which is today's behaviour." On the team path "the renewal runs as a conversation and leaves the paperwork to the customer's team." A replay of Camellia's real book is identical before and after (4 offers, 1 hold, 15 no action, 0 writes).Talking to the tenant and sending the paperwork become two separate things, and Camellia does not change.
2026-10-08Fede session f86757cfThe first statement of the split: "the customer isn't ready yet for fully autonomous sending out the leases. […] a way to switch it so that it only sends communications out, not the contract yet, and the team would still have to do the contract."Origin of the paperwork-sender setting. Bias: "reducing new work as much as possible".
2026-10-08Fede session f86757cf"I don't want to necessarily make a mess here, but just have a way to kind of like slowly walk towards fully autonomous renewals."The graduated path the 10/12 levels recast.
2026-10-08Fede session f86757cfOn first scope: "for V1 I need a version we can finish in the next 24 hours" and "this might need a bit more thinking" (on the weekly heads-up and opt-out mode).The heads-up mode Jay asked for was set aside. See Open threads.
2026-10-08Fede session f86757cfOn proof: "willows is just the single property so not enough conffidence" and "we need to probably standarize and clean up actually not add more".Leads to the testing playbook and two standard sandbox companies.
2026-10-08founders standup (transcript)Fede on today's Camellia flow: "renewals are like fully autonomous right in [Camellia] where we do everything. We decide, we send the offer and execute." Then: "I'm decoupling the send the document part from the communications […] your team does the paperwork, and once you're comfortable, we graduate you to paperwork".Autonomy becomes a ladder a customer climbs. Camellia is the top.
2026-10-09Western Slope go-live pageApproval cadence decided: one batch email on the 1st of each month, with no setting. Fede on the first sample: "very crowded, doesn't tell you who the tenant is."The reviewer list becomes one monthly email.
2026-10-09PR #18321The daily scan "opens ONE monthly batch per Supervised company as a held message and emails the company's Renewals reviewers through the existing held-message door." "Month-to-month (no end date) leases are not in the list (Fede 2026-10-09)".The monthly reviewer list exists. Month-to-month tenants are left off it.
2026-10-09Fede session 1fcfe5deOn approvals to staff: "I don't know if I like the one email per approval. […] it makes more sense to batch it so you know every I don't know if it's every month or every week". And on the timing: "I don't think we want a setting for this."The monthly reviewer list is born. No setting for its timing.
2026-10-09Fede session 1fcfe5deOn what the review needs: "let's not over engineer or over build. […] just basic ability to change things like you know the new rent at least". And: "we should not include month-to-month in it."Review means renew yes or no and change the rent. Month-to-month tenants are not on the list.
2026-10-10PR #18552 [urgent]Incident after flipping a sandbox company to Supervised: "33 per-tenant pages to Fairhaven staff". "Only one of four callers carried the Supervised check. The shared sender had none."Supervised never pages office staff per tenant, from any caller.
2026-10-10Fede session 1fcfe5deOn finding per-tenant emails in the build: "i said no per tenant emails" and "why do they exist".Per-tenant office emails removed (PR #18552).
2026-10-11Fede session 1fcfe5deOn the build's email-first flow: "Well, isn't this a text experience? Primary?" and "is the email experience what we have in Camellia, or did you make this up?"Tenant contact is text first; email is for the office.
2026-10-12memory ruling (PR #19038)Renewal texts lose the STOP footer: "renewal texts are not marketing".Small wording rule.
2026-10-12levels-of-autonomy page"paperwork is no longer tied to Live (Fede, 10/12)". Levels 0 to 4 are presets of three settings; "who decides the terms" becomes its own setting; the Off/Supervised/Live gate becomes a one-week soak.The newest design.
2026-10-12Fede session 1fcfe5deOn review pages: "we would prefer one review page for all".One customer review page; the admin page stays internal.
2026-10-12Fede session 1fcfe5deThe reviewer list, 11:46. "we should have a way to list who are the people one person or multiple that review and approve […] renewals so in this case it's Jay and Kat so we should send a single email to both of them […] we also want to have a backup link that goes to a review page".One email to a named list of reviewers, with a review page as backup. The MVP for Western Slope.
2026-10-12Fede session 1fcfe5deA tenant replied to a test text and nothing happened: "what hapenens if someones does want to renew" and "or if theys submit NTV on the website". Then: "for no, let me think about it more" / "dont build yet" / "lets design it".The tenant-reply gap is named. Design before build.
2026-10-12Fede session 1fcfe5deThe simplification, 14:55. "I think this is too complex and probaly need to simplifyi or consolidate concepts" and "im not sure we want to tie "live" mode with sending the paperwork or not".Reverses the 10/8 ladder where paperwork was the last step of Live. Paperwork is its own setting.
2026-10-12Fede session 1fcfe5deOn Supervised: "it's an in-between step and then the goal is to get everyone live right".Supervised is a short soak, not a destination.
2026-10-12Fede session 1fcfe5deOn levels: "levels of autonomy where the first level would be just sending out the communication. […] Camellia is kind of like the ultimate level where everything's automatic except negotiations."The levels recast. Camellia is the top level, not a special case.
2026-10-12Fede session 1fcfe5deOn the next step: "How do we step up a customer that might not be ready?" and "maybe these are just kind of like settings or something".Levels may be settings. Still open (D5 on the levels page).
2026-10-12Fede session 1fcfe5deThe expected notice-to-vacate reply: "Sorry to hear you're leaving or something like that. And then guiding them like, okay, the next step is to do a formal notice to vacate on your tenant portal".Clara guides to the official notice in AppFolio, which triggers the other automations.
2026-10-12Fede session 1fcfe5deThe plan for the week: "since we're on supervised mode I would expect at least for the first week or so that it will hold the message messages and then me and Hera would approve each one". "Hera" is a speech-to-text garble for Gera.Week 1 Supervised with Fede and Gera approving.
2026-10-12Fede session 1fcfe5de"we would turn autonomous […] once the customer approves or changes or whatever they do, it just sends it out. And there's no uh, engineering in the loop. Anymore. That will be like by week two."Week 2 goes autonomous on the customer's approval.

Reversals and tensions

TopicEarlierLater
Re-offer to month-to-month tenantsADR-0046 (6/3): "send a fresh offer for the next month"Fede 9/5: "i dont want to offer anything, just roll mtm."
Approval before sendingFede 9/3: "no one is going tmanually review" (about AppFolio facts)10/12: a named reviewer list approves each renewal. [inference] These fit if AppFolio facts need no review and owner terms do.
Autonomy for Western Slope10/7 Fede: "Send in a list. […] Send it out." (proceed unless stopped)Same day Gera: "we definitely would want to have some sort of supervised mode right now." Decided 10/8: hold every message until approved.
Autonomy vs a queue (9/4)Fede: "go back to basics. And remove everything and go all autonomous again for Camellia"Gera, same day: "it's better to say something than to keep tacking onto this giant queue that we've been building on human review"
Paperwork tied to Live10/8 ladder: the team does the paperwork "and once you're comfortable, we graduate you to paperwork"10/12 Fede: "im not sure we want to tie “live” mode with sending the paperwork or not"
Switches9/2 Fede: "this should always be on, remove the feature flag andd deploy"A per-building autonomous flag, arms, and a new paperwork setting exist; the levels page lists them under "Not settings: delete or fold"
Held messagesSupervised design: "A held message expires after 24 hours if nobody acts."10/12 levels page: "A held reply never dies silently." (design, not built; the 10/9 fix was parked)
Engines8/31 a separate holdover process was added; Fede: "i dont want a standalone rogue process"9/3 Fede: "i dont undertadn why there are 2 engines"; one engine merged the same day
Contact channel4/21 plan led with voice9/28: text first, no opening call; 10/11 Fede: "isn't this a text experience? Primary?"
Who is bad enough to hold5/21 and 7/23: two months owedJay 10/7: hold when the balance is above zero; Sean 9/30 pitched 60 days
Reminder cadenceFede 8/31: "reminder 3 times like we do today with leases. business days only. once per day max."The levels page says the cadence doc and the code disagree (48h/5d vs 24h/7d). The ruling is dated 8/31 on one page and 9/3 on another.
Quiet wrap-up7/17: wrap up quietly8/13 Fede: never give up on a tenant; the audit calls the two "a straight contradiction"
Legal gate6/22: "Do NOT add a legal/eviction gate"7/20: "Legal stuff needs an ADR first — very delicate."
Stated vs built6/8 Fede: "I'm gonna turn on the autonomous renewal"; 7/23 "its already on"ADR-0066 (6/22): "Camellia runs holdover-only (autonomousRenewalEnabled off), so no autonomous renewal offers have ever gone to a real tenant"
Module order9/4 maintenance, leasing, renewals; 9/18 leasing, maintenance, renewals last9/23 renewals before maintenance (customer's phone contract). 10/1: renewals first.
Asking staffCamellia retro 9/4: do not ask staff who will not answerWestern Slope reviewers must answer each month

What the customers said

Camellia (single-community owner, live since spring)

DateWhoSaid
2026-07-08Gera to Joanna"Would you want it, Joanna, to go to you, where maybe you send it, um, or you confirm it, and then it would send, or do you want us to just send it on your behalf?" (no answer recorded)
2026-07-16Joanna"if they owe, like, 2 months or more, they're getting sent a 10-day, and they're not being offered a renewal"
2026-07-16Kenya"I think we were saying to countersign within 72 hours"
2026-08-13Spanish-speaking tenants (relayed)"who is Clara"
2026-08-20Kenya"we could still potentially keep her and just have her month to month for September, and then she renews in October"
2026-09-17Joanna"I don't think we should offer them right now, anyway."
2026-09-17Kenyaasks for a 'transferred' outcome "so it shows that they stayed"

Western Slope (centralized manager, planned Supervised go-live 10/14, first set for 10/12)

DateWhoSaid
2026-09-30Jay"there's certain tenants that have bad payment history that we just want to go month-to-month with, we don't want to lock them in."
2026-09-30Jay"We need to schedule a move out in that folio" (wants non-renewals to start the next steps automatically)
2026-10-07Jay"I want to renew people at zero" (balance zero)
2026-10-07Jay"If we haven't, you know, redirected her or told her no, then she goes ahead." (the heads-up ask)
2026-10-07Jay"Clara will build an agenda, we'll review the items she has escalated in our, you know, our weekly or monthly renewal meeting"
2026-10-07Jay"building the templates is out of scope"; Lincoln and Courtyard stay manual; questions go to "Kat, and she'll escalate to me if she needs to."
2026-10-07Jay"It used to be $100, and now it's $150." (month-to-month fee)

Situs Group (8/25, not live): "How do we hone in on the unknown still, where, like, they haven't made a decision?" and a fear of a "fat finger" rent error, answered with human-in-the-loop first.

Open threads

  • Tenant reply gap (10/12). A yes, a no, a counter or a notice to vacate by text or website reaches no one. Fede: "dont build yet", design first. A fix for the empty reply after a decline is in flight.
  • Levels page decisions D1 to D6. Which messages are held in week 1; whether "who decides terms" is a setting; office notice when a tenant answers; held messages that never expire with a re-ping; levels as three settings or one picker; the first-list rent rule (Fede leans flat).
  • Western Slope facts. About 36 to 40 lapsed leases (Fairhaven showed day-one pages); market rent below current rent; two contact numbers for Kat that differ; the month-to-month fee ($100 vs $150) is not yet a stored setting.
  • Weekly heads-up and opt-out mode. Jay's ask; Fede 10/8: "this might need a bit more thinking".
  • Notice to vacate from a holdover tenant. "OPEN DECISION (confirmed still open 2026-09-23)". Also unknown: whether an emailed notice starts move-out with no human (not covered by any test).
  • Aging unanswered escalations; tenant who never answers and nobody is told; counter-offers and stale offers after a price drop.
  • Legal and eviction gate. Backlog only; no ADR yet.
  • Whether to offer renewals to month-to-month tenants at Western Slope.
  • Camellia vacated unit 522 charge and back-bill decision.
  • Renewal calls and texts are not logged back to AppFolio (raised 9/1 and by Situs 8/25).
  • Replay check as a CI gate. The Camellia replay diff is still to be made required.
  • Unrun ADR-0046 canary.
  • Go-live slip. Monday 10/12 became Wednesday 10/14; week 1 Fede and Gera approve every message, week 2 Live.

Sources

  • Docs-site pages in the docs artifacts folder: one-doc renewals register, quality system page, Supervised design, Western Slope go-live page, the 10/12 levels-of-autonomy draft (uncommitted), testing playbook.
  • ADRs: 0025, 0036, 0046, 0047, 0066, 0091, 0100, 0108, 0122, plus the notice-to-vacate holdover planning doc.
  • PRs and issues: #62, #65, #1376, #2573, #3985, #4020, #6721, #6722, #6902, #7101, #12897, #14897, #14899, #15310, #15656, #17243, #18012, #18017, #18039, #18040, #18041, #18058, #18321, #18427, #18552, #19010, #19038.
  • Slack #transcripts raw per-speaker threads, 2026-04-26 to 2026-10-12, read with the Keychain token, plus Fede's own chat threads (voice notes unlabeled).
  • Claude sessions in this project directory only: 2c19a3c3, a566db0c, 28bc997e, 18c2fec2, f86757cf, 1fcfe5de.
  • Method: each quote was checked as a substring of the source text after case and punctuation are ignored; tenant names and phone numbers removed.
K. Camellia production pass, full report (read-only, 10/12; initials only)

Read-only pass over production: renewal records, leases, conversations and the email log in the production database, plus the 16 Temporal workflow histories that still exist. Tenants appear as initials plus unit, staff as initials. This extends the 09-28 doc sections "What the data says" and "Camellia month-to-month rollover" and does not repeat them. Evidence ids are in the index at the end.

TL;DR

  • Fede's hunch holds. 7 of 40 tenants who got the offer text ever wrote back (18%). Since June, 34 calls produced 0 decisions.
  • Silence is not "no". 12 of 34 silent tenants renewed anyway, 9 of them by signing the offer Clara sent. The letter plus the portal link does most of the work.
  • The bigger leak comes after a reply. Of 15 tenants who engaged, Clara closed 6 cleanly and 1 with the office's help. She dropped 6.
  • Biggest wins: act on every answer the same day, stop texting people who already answered, make every hand-off reach the office, and offer Spanish.
  • Since 9/28: 3 more tenants signed (S.B. 215 is probably a fourth). The sync closed 8 stale records on 10/2 and 10/6. 1 workflow crashed and 1 lease rolled to month-to-month. No new rounds have started since 9/18.

---

1. The workflow as it really runs

Daily scan, 8:30 am Denver, 7 days a week
  └─► prepare the offer in AppFolio ──(fails)──► hand-off to the office
        └─► letter text with PDF ─► call about 1 minute later
              └─► reminder on day 2 ─► reminder on day 9
                    └─► nudge at lease end −60 (only runs that reach it after 10/1)
                          └─► nudge at −30 ─► nudge at −15 ─► lease end
Tenant says "yes" ─► 14-day wait for a signature ─► office email "said yes, nothing signed"
Tenant silent     ─► workflow exits quietly ─► daily scan rolls the lease to month-to-month
StepDesignWhat happened at Camellia
OpenDaily scanUntil late June, staff opened rounds by hand, mostly on weekday afternoons. Since then the scan opens them in bursts (for example 7/2, 8/2, 9/1, 9/3). Lead time ranged from 8 to 119 days before lease end.
Prepare offerA failure goes to the office27 failure hand-offs. 7 rounds never got an offer.
Offer textSent inside send hours51 offer texts to 40 tenants, 11 of them duplicates. None at night.
CallAbout 1 minute after the text50 calls. 7 reached the tenant.
RemindersDay 2 and day 969 sent, 38 of them on a weekend.
Nudges−30 and −15 days (−60 is new)18 sent: 14 at 6 pm, 4 at 8:30 am.
"Yes"14-day wait, then an office emailNothing goes to the tenant during the wait. Two such emails so far (P.D. 607, S.B. 215).
SilenceExit, then month-to-month4 rollovers: 3 on 9/5 and 1 on 9/30.
EngineEvery live round has been a Temporal workflow since 9/316 histories readable: 11 running, 4 completed, 1 failed.

2. The funnel

The window is 58 renewal rounds whose first touch fell between 4/22 and 9/18 (lease ends 4/30 to 12/31). State as of 10/12.

StepRoundsWho
Renewal rounds58One round = one tenant and one lease end
Offer never created7J.B. 306, G.S. 204, L.F. 416, I.G. 515, M.S. 220, C.H. 317, B.S. 409
Clara stood down because the office had it2J.S. 404, S.D. 417
Contacted4940 by text (most also got a call), 9 by call only (April and May)
Engaged157 in writing, 7 on a live call, 1 callback
Renewed2417 after Clara's outreach, 7 done by the office in AppFolio
Gave notice16
Moved to another unit4
Month-to-month2L.G. 522, G.S. 204
Still open10Lease ends 10/31 to 12/31
Stuck / unknown1 / 1B.S. 409 / T.B. 517

How replies were counted. "Replied" means at least one written message from the tenant in the renewal thread after the first offer. That is a text, or an email to the manager that landed in Clara's thread (P.D. 607). "Engaged" also includes a live call where the tenant talked about the renewal, and a callback about it. Screeners, voicemail and household members do not count.

Renewal rate. Across all rounds, 24 of 44 decided rounds renewed (55%); "decided" means renewed, gave notice or moved units. On the 09-28 doc's June 25 to December 31 cohort, the rate is now 14 of 36 (39%); the doc had 9 of 32 (28%).

Changes since the 09-28 doc. The doc's list of leases was not stored, so the "today" column below is a rebuild: 50 leases versus the doc's 52.

09-28 docToday
Renewed914
Gave notice1917
Moved units45
Month-to-monthn/a2
Still deciding1510
Stuck, no offer31
Never contacted20 (B.S. 409 is counted as stuck)
Unknownn/a1
What changedDetail
SignedL.L. 410 and D.S. 505 signed 10/2 and were countersigned 10/6. C.D. 512 signed 10/2. Its workflow still waits for the countersignature, though AppFolio already shows the new end date (10/31/2027). *Inferred:* when the 14-day wait ends on 10/16, the office may be asked to chase a lease that is already done. S.B. 215's lease now ends 10/31/2027; the signing date is unknown.
SyncClosed 8 stale records on its own: 7 on 10/2 and I.G. 515 on 10/6. Renewed: P.D. 607, B.G. 608, S.D. 417. Left their unit: J.B. 306 and L.F. 416 (moved units), M.S. 220 and C.H. 317 (gave notice).
NewE.L. 302 gave notice (10/1). G.S. 204 rolled to month-to-month (9/30).
BrokeB.S. 622's workflow crashed 10/1 because the lease had been archived.
QuietNo new rounds since 9/18. The 5 leases ending in January 2027 enter about 11/2.

3. Engagement verdict

Engagement is low, as Fede thought. But more renewals are lost after a tenant answers than by tenants staying silent.

MeasureValue
Wrote back, of 40 texted7 (18%)
Any engagement, of 49 contacted15 (31%)
Calls since June / decisions from them34 / 0
Silent tenants who renewed anyway12 of 34 (9 on Clara's offer)
Engaged tenants Clara closed cleanly6 of 15 (G.K. 509, J.B. 516, T.H. 104, S.R. 601, S.K. 603, A.S. 503)
...closed with the office's help1 of 15 (E.N. 210)
...dropped by Clara or the hand-off6 of 15 (S.B. 215, M.G. 504, P.D. 607, V.G. 614, C.Z. 120, E.A. 114)
...hostile or hung up2 of 15 (D.F. 105, R.D. 308)

Replies follow a touch. 5 of the 7 written replies came within 20 hours of one: the letter (S.K. 603, 40 min), reminder 1 (A.S. 503, 0.8 h), reminder 2 (S.B. 215, 1.6 h; E.N. 210, 19.5 h), and the 30-day nudge (V.G. 614, 3 min). Weekend texts are not the problem: 2 replies came on a Saturday.

When the call went outCallsReached the tenantDecisions
Weekday, 12 to 5 pm1954
Weekday, before noon2110
Weekend morning510
Evening500

*Inference:* most of the afternoon calls were in April and May. Staff had started those rounds by hand, 8 to 54 days before lease end. Time of day, lead time and staff choosing the tenant are tangled together, and this data cannot separate them.

4. What works

  • A live conversation converts. All 4 tenants reached on a weekday afternoon in April and May said yes and signed. G.K. 509, 8 days before lease end: Clara: "which term works best for you…" Tenant: "A year." S.R. 601: "One year." T.H. 104: "I'm gonna go for the 12-month."
  • A clear "no" becomes a notice the same day. S.K. 603, 40 minutes after the letter: "…so I will not be renewing". Clara sent the steps to give notice in the portal. Five hours later: "I just submitted my notice to vacate in the portal."
  • Negotiation works when it reaches a person. E.N. 210 asked about the 1-month-free special (7/20, 8:50 am). The office answered through Clara at 9:41 pm that day: "they've approved a one-time exception: 2 weeks free". After an addendum on 7/23 came "Great thanks just signed!!" (7/24).
  • Reminder 2 and the 30-day nudge pull replies. S.B. 215, 1.6 hours after reminder 2: "Yes sorry I'm resigning". V.G. 614, 3 minutes after the 30-day nudge.
  • The text and link work without a conversation. 9 tenants who never replied signed the offer Clara sent, for example L.L. 410 and D.S. 505 on 10/2.
  • The sync cleans up. On 10/2 and 10/6 it closed 8 records the office had already settled in AppFolio, with no human step.

5. Failure modes

#FailureCountVerbatim exampleTag
1Empty or failed replies0 empty. 3 threads where Clara admitted a tool failure (E.N. 210, E.A. 114, T.H. 104). 2 replies swapped by the safety check.E.A. 114 on a call: "I wasn't able to flag that just now, so I'd suggest reaching out to the leasing office directly". T.H. 104 said thank you twice ("The management here is truly world class"). Each time the safety check blocked Clara's reply and swapped in "I'm looping in your property manager… They'll follow up shortly." No one was looped in.bug
2A yes with no follow-up3 (S.B. 215, M.G. 504, P.D. 607)M.G.: "Yes thank you" to the 6-month term. Clara: "You'll get a recap text with the updated details and your signing link." It never came: AppFolio blocked the term change ("Out for Signing"). The 8/15 nudge still pitched the 12-month. The lease rolled to month-to-month 9/1. She later signed a 6-month lease through the office. S.B. got "You're all set", then 14 days of silence. The office email then said "the renewal window has run out" with 35 days left.bug + product gap
3A no without notice guidance0S.K. 603's no got the portal steps (row 2 of "What works").works
4aEscalations sent but not answered in the thread3 escalations, 2 tenantsP.D. 607 asked for $1,000 (8/3), then chased (8/6). Clara replied: "I've sent them a second nudge flagging the August 9 deadline." The thread never got an answer; the office settled it in AppFolio later. M.G. 504's 8/21 request for "a physical copy" has no recorded action. E.N. 210's escalation was answered the same day, and V.G. 614's was handled in AppFolio.product gap
4bThings that never reached the office7E.A. 114 needs Spanish. M.R. 303's household asked for mail. B.G. 608's new number. C.Z. 120's dropped callback. D.F. 105 thinks it is a scam. T.H. 104's fake loop-in. V.G. 614's "I've taken you off the list".bug
5Texts after the tenant answered6 tenants, plus 1 late readA.S. 503: "I signed my renewal yesterday! Did I miss something?" V.G. 614 had said she signed a paper 6-month lease. The 15-day nudge went anyway: "Please do not text me again". E.S. 518 and R.R. 224 had notices on file since 7/7, yet got this on 7/31: "You can still renew at $1,750/mo". P.D. 607 and M.G. 504 also got nudges after answering. B.M. 420 is a different bug, a late read: her notice was dated 8/1 in AppFolio, but Clara saw it only on 9/11, so the nudge and the month-to-month notice went out anyway.bug
6Wrong person3B.G. 608's former roommate: "This phone number is no longer associated with Apartment 608… more than happy to share her contact info". Clara: "I'm not able to accept contact info for another resident through this channel". Staff had asked for that number 2 hours earlier. A nudge still went to that phone 7/28. M.R. 303's household member: "just send me a piece of mail" was refused.product gap
7Holds that expired silently0No renewal holds exist at Camellia, and supervised review is not used.n/a
8AppFolio before or instead of Clara1 call; 13 office renewalsS.M. 616 called about an AppFolio renewal email (6/8). Clara: "I don't see an active renewal on file for you right now". The transfer that followed ended in "Hello? Hello." Within Clara's rounds, 7 renewals were done by the office in AppFolio. 6 more office renewals never had a Clara round. *Inferred:* AppFolio sends its own email for offers the office creates, and Clara cannot see them.product gap
9Month-to-month drift4 rolloversNew since the doc: G.S. 204 rolled on 9/30, and its offer never existed. 8 active leases now have no end date. P.C. 118 and P.W. 111 still say month-to-month although both renewed.bug
10Duplicate offers11 extra texts, 6 roundsOn 5/26, P.C. 118 and B.G. 608 each got 3 letters plus 1 offer text within 90 minutes. D.M. 620 had the full sequence from 7/13, then got a new letter and reminder again at the 9/3 cutover.bug
11Timingsee detailCalls went out at 8:30 am, including Sunday 8/2: "Shut up, scammer." (D.F. 105). Others: Sunday 7:44 pm (3 calls), Friday 9:23 pm. A.P. 212 got the offer 14 days out; the 12/31 group got it 119 days out. Silent gaps: leases ending 11/30 hear nothing from 9/12 to 10/31 (49 days), 12/31 leases from 9/12 to 11/30 (79 days). Office "ready for your signature" emails went out Friday at 8:21 pm.bug
12Replies on another channel4C.Z. 120 called back a minute after a Sunday voicemail: "I think you just sent me a voicemail today for, um, our renewal". The transfer dropped: "Hello? Hello?" P.D. 607 and V.G. 614 emailed the manager, and those emails landed in Clara's thread. T.H. 104 texted into the call thread at 3:37 am.product gap

Beyond the checklist

FailureDetailTag
Spanish-speaking households5 households show Spanish signals. E.A. 114 asked for Spanish. B.M. 420 called the line in Spanish. R.P. 201 answered in Spanish. Y.C. 610's call screener and L.G. 522's voicemail greeting are in Spanish. Every renewal text and call was in English. On the renewal call Clara says "I'm only set up for English at the moment", yet the inbound line switched to Spanish for B.M. 420 on 6/3. None of the 5 has renewed: 2 gave notice, 1 rolled to month-to-month, 2 are open. The language field is blank on 110 of 121 records.product gap
Offer never createdG.S. 204's offer failed 7/13 because a signer had no email. The 09-28 doc covers the 9/15 nudge for that missing offer. New since then: the clear "add an email" notice reached the office only on 9/16, and the lease rolled to month-to-month on 9/30. A 7/13 hand-off may also have gone out, but the email log starts 9/12. L.F. 416 had 10 records in a July retry loop. B.S. 409 has been stuck since 9/3, with the lease ending 11/30.bug
Wrong copy or stateT.B. 517's offer: "your lease is coming up on your lease end date". B.G. 608's nudge said "about two weeks away" with 3 days left. S.B. 215's text "yes" was recorded as a voice intent. P.D. 607's record flipped to "Tenant signed" on 7/31, but P.D. had not signed. The 8/14 office email said "agreed verbally", but P.D. had made a counter-offer that was never answered.bug
CrashB.S. 622's workflow failed 10/1 at the 30-day nudge: "Lease … not found in property". The lease had been archived and another tenant moved in 9/1.bug
A renewal call reached a non-tenantOn 6/26 a renewal call reached a Spanish-speaking apartment hunter. Clara's leasing side booked a same-day tour, while the renewal voicemail line ("Sorry I missed you") also played. That person moved into unit 201 on 7/1. No renewal round matches this call.bug (cause unknown)

6. The office's side

What the office receivedCount
"Completed" notices (S.J. 411, D.F. 203, M.A. 511, E.N. 210, J.L. 401)5
"Agreed verbally, nothing signed" (P.D. 607, S.B. 215)2
"Rolled to month-to-month" (M.G. 504, L.G. 522, B.M. 420, G.S. 204)4
"Blocked, a signer is missing an email" (G.S. 204)1
Offer-preparation failure hand-offs27
Renewal escalations from tenant threads (E.N. 210, P.D. 607 ×2, M.G. 504, V.G. 614)5
  • Answered fast once: E.N. 210, the same day. That was the one negotiation that ended in a signature.
  • Not answered in the thread:
  • P.D. 607's counter-offer: 2 escalations, no reply in 11 days. The office settled it in AppFolio later.
  • M.G. 504's request for a paper copy.
  • V.G. 614's paper lease. The office handled it in AppFolio on 8/24.
  • Still signing on paper: V.G. 614's 6-month lease was signed on paper.
  • Renewing on its own: 13 renewals ran through AppFolio without Clara.
  • Odd send times: emails went out at 8:21 pm. Two "Renewal completed" emails failed (a missing mail key) and were re-sent 3 minutes later.

7. Ranked improvements

RankChangeEvidenceTag
1Stop every reminder and nudge the moment the tenant answers, signs, says they signed on paper, gives notice or says stop. No "you can still renew" text after a notice. Read AppFolio notices within a day.6 tenants (row 5); B.M. 420's notice was seen 41 days latebug (fix, no switch)
2Keep every promise made in the thread: the recap text and signing link, the term rebuild, or a same-day note to the office when AppFolio blocks it.M.G. 504, S.B. 215bug (fix, no switch)
3After a "yes", chase twice during the 14-day wait instead of going silent.S.B. 215, P.D. 607product gap (improves a live flow)
4Every hand-off reaches the office, even when the tool fails. Never claim "looping in your property manager" without doing it. Tell the office about a blocked offer the same day, in plain words.E.A. 114, T.H. 104, G.S. 204, B.S. 409bug (fix, no switch)
5Spanish offer, reminders and renewal call. Set the language from the inbound line or a Spanish voicemail greeting.5 households, 0 renewalsproduct gap
6Drop the 8:30 am opening call, as the 09-28 doc recommends. If voice stays, one weekday-afternoon call about 30 days out, for silent tenants only.34 calls since June, 0 decisions; afternoon 4 of 19 vs morning 0 of 26product gap
7Fill the silent gap: give running workflows the 60-day touch.Nov/Dec leases hear nothing for 49 to 79 daysbug (fix, no switch)
8Clean up the records: no duplicate letters on retry or cutover; guard against the missing-date placeholder; exit quietly when a lease is archived; record the real channel; a counter-offer is not a "signature"; correct "days left" copy.rows 10 and 11, crash, wrong-copy rowbug (fix, no switch)
9Accept a new number or "mail it to me" from a household member and pass it to the office.B.G. 608, M.R. 303product gap
10A counter-offer loop with a deadline set before AppFolio's signing deadline.P.D. 607. Every offer equals current rent, and 26 of 51 priced offers sit above market (median +$150).product gap
11Callbacks about a renewal are handled on the line, not transferred into silence.C.Z. 120, S.M. 616product gap

The 09-28 doc already recommends email as a second offer channel. The new data supports it: 2 of the 7 written repliers emailed the manager, and 18 of 121 records have no email on file.

8. Method and caveats

  • Sources:
  • Production renewal records (121), leases (162), conversations for 79 people, and the email log.
  • The 16 Temporal histories still kept (about 40 days of retention).
  • Workflow code at origin/main.
  • All reads only.
  • Rounds: Records were grouped into rounds by target lease end, with 4 targets fixed by hand (C.Z. 120, G.S. 204, T.B. 205, J.S. 404). Outcomes were assigned by hand from record state, current AppFolio lease rows and messages.
  • Call labels: Call outcomes were labelled by matching phrases in the transcripts, then 4 were fixed by hand: D.F. 203, V.G. 614, M.R. 303, R.P. 201.
  • Blind spots:
  • The email log starts 9/12, so office emails before that cannot be confirmed.
  • Lease rows are today's snapshot, not history.
  • Small numbers: Every percentage rests on fewer than 60 rounds.
  • Inferences: Inferences are labelled. These are the main ones:
  • Why the afternoon calls worked.
  • That AppFolio sends its own emails.
  • That the 9/3 batch opening 58 to 119 days out was a one-off tied to the cutover.
  • That a Spanish screener or voicemail greeting means a Spanish-speaking household.
  • That C.D. 512's wait will page the office on 10/16.
  • Redaction: Initials only. One tenant phone number survived the first redaction pass inside an email. It was scrubbed from the local copy and is not quoted here.

---

Evidence index

WhoIds
G.K. 509 / J.B. 516 / S.R. 601 / T.H. 104 callsconv_voice_faa909e2-ddb8-4038-91a7-f3aa3f16116e, conv_voice_8ff1882f-ce2d-479e-b56a-4d0162b2a97e, conv_voice_ebd0e13d-63b8-4432-9341-2aab10b8b768, conv_voice_6a15e577-975c-4e70-aeba-1f8c252603ad (also T.H.'s 5/27 blocked replies); saga_4c8d1956, saga_25395c2a, saga_a35c4cef, saga_6f3a772f
S.K. 603conv-renewal-tenant_61656d50-f15e-4e2a-ab34-05295e33c562-1782323715356; saga_911286b7, saga_d92aeeeb
E.N. 210conv-renewal-17736259534620024-1783711349011; saga_8f5eeae8
S.B. 215conv-renewal-17736259534620027-saga_cba1063a-a014-4959-96b3-1a5a28374125; saga_cba1063a; workflow renewal-lease_d6d15602-ba2e-4e3e-abfb-2c8a01f6d8b9-2026-10-31
M.G. 504conv-renewal-17736259534620070-1782258013197; saga_fe7b4e8f (CHANGE_TERM_BLOCKED 8/5)
P.D. 607conv-renewal-17736259534620090-1783711828815; saga_fba0927a
V.G. 614conv-renewal-17736259534620095-1782258178956; saga_7a698406, saga_47f350e4
A.S. 503conv-renewal-17736259534620069-1783002874143; saga_e0116702
E.S. 518 / R.R. 224conv-renewal-17736259534620081-1781302987376, saga_e015ff8d / conv-renewal-17736259534620033-holdover-lease_50cd376f-3f1e-46d0-98ae-9301b2f46d21, saga_bbae8a97
B.G. 608conv-renewal-17736259534620091-1779833522875 (and …1779828358269, …1779830122293, …1779833521958 for the duplicates); saga_7b75fad0
M.R. 303conv_voice_f6e74c6b-84ce-40c3-b041-7fbf25f4a66d; saga_0e76cffa; workflow renewal-lease_de05329b-2b3a-4f64-883d-cf13a3ad3364-2026-12-31
E.A. 114conv_voice_fc153c0b-bce6-47f9-9d86-af6c032e6eea; saga_8454bf4d; workflow renewal-lease_400b86d9-3bf0-4818-b8a5-3126c0ed9b55-2026-11-30
D.F. 105conv_voice_d2c50186-050a-40f4-8722-6d29d24bb68a; saga_5e5c4fec; workflow renewal-lease_626f847b-147b-4f8b-a31d-a926b46f5f98-2026-10-31
C.Z. 120conv_voice_783a7a9a-d18d-4dc4-9ba0-67318ad65dd3 (voicemail), conv_voice_ade27c7d-b195-481b-a2df-780f56ec7980 (callback)
S.M. 616conv_voice_5d7cb67d-3661-435d-9e45-38fcd966bf6d
G.S. 204conv-renewal-17736259534620021-saga_33866181-674f-44b0-8855-9c645c51cc5b; saga_33866181
L.F. 41610 records: saga_eadb0a13 … saga_e17df2a9
B.S. 409saga_67326c3c; workflow renewal-lease_a2d3f5f8-e7d5-433e-895f-7035603bdc84-2026-11-30
B.S. 622 (crash)saga_533f66e2; workflow renewal-lease_3505f7d6-a674-4ab5-90c3-b403a2062e51-2026-10-31
T.B. 517conv-renewal-17736259534620080-1784127808366; saga_b03479b6
D.M. 620conv-renewal-17736259534620100-1783953223007 (7/13), conv-renewal-17736259534620100-saga_8f533020-… (9/3)
C.D. 512 / L.L. 410 / D.S. 505workflows renewal-lease_98be4668-9559-4a4a-a8c9-f4b98666517f-2026-10-31 (running), renewal-lease_4871ca18-39a2-4d93-bd97-02f59be866c6-2026-11-30, renewal-lease_bbbc3347-f422-4199-80a8-3570d8e13609-2026-11-30
R.P. 201 callconv_voice_94e6e07b-2acf-4a35-977f-de171590d271
D.B. 609 / C.H. 618 screenersconv_voice_c3ce06c9-636f-4826-9a59-8a9d340b9017 ("you've reached Cloaked AI"), conv_voice_9f123e5c-b045-48c0-ab88-54557de124c1 ("Please say who you are")
L. Past decisions, from the raw transcripts

Every renewal decision since June, read from the raw transcripts of team and customer calls (#transcripts, per-speaker text, not the recaps), the bridge channel, and Fede's own words in Claude sessions. Quotes are verbatim. "Customer stated" rows are the customer's policy, not ours. 281 meeting threads read, about 100 with renewal talk; 427 quotes checked; 42 decisions below.

Still in force. Never below current rent (7/16). AppFolio is the truth (7/28). No outbound to a delinquent tenant unless the customer approves the list (8/31, 10/14). One renewal engine (9/3) and the replay lab (9/4). Camellia stays fully autonomous. New customers get texts, not calls (10/5). Western Slope: Supervised, messages only, their team does paperwork, rent flat (10/7 to 10/12). Review offers On by default (10/14).

Gap. The 9/19 "customers never review, review mode TEMPORARY" ruling has no raw transcript, channel or session source (checked 2026-10-14 against 281 transcripts); the word "temporary" comes from the 8/30 Camellia rollout safeguard. It was superseded on 10/8 when Gera and Fede agreed customers can review.

DateSourceWhoDecisionQuoteSuperseded by
6/03Standup/call transcriptSean, FedeCamellia: a tenant who does not sign goes month-to-month; Clara changes it in AppFolio."then Clara will go in and change it to month-to-month in AppFolio." (Sean)Still in force; Western Slope said the same on 10/7.
6/08Standup/call transcriptFedeCamellia: renewals go fully autonomous, no approvals."after this call, I'm gonna turn on the autonomous renewal, so I don't have to approve them anymore."Still in force at Camellia (Fede 10/6: "Camellia should be fully autonomous"). New customers start Supervised instead (10/7 on).
6/08Standup/call transcriptFedeCamellia: a tenant with more than two late payments is flagged for human review."Someone has more than two late payments." / "Yeah, it's flagged for human review, yeah."Refined 7/16 and 8/4 (balance rules).
7/16Standup/call transcriptFedeCamellia: fully automatic; Clara calls and texts the letter; month-to-month costs $100 more."It's fully automatic now. Like, I'm not approving anything." / "And that has a $100 premium."Calls dropped for new customers 10/5. Western Slope fee is its own ($150, 10/7).
7/16Standup/call transcriptCamellia staff (customer stated)Camellia: a tenant who owes 2 or more months gets no renewal until caught up."if they owe, like, 2 months or more, they're getting sent a 10-day, and they're not being offered a renewal"Tightened 8/31.
7/16Standup/call transcriptSeanNever offer less than the current rent."the rule is we never offered less than what they're already paying."Still in force (7/23).
7/23Standup/call transcriptSeanNo step-downs; renew at the existing rate or higher."on renewals, we're not stepping people down. They renew at their existing rate."Still in force.
7/28Standup/call transcriptFedeAppFolio (the PMS) is always the source of truth."the BMS data is always a source of truth."Still in force.
8/04Standup/call transcriptSeanA balance older than 60 days holds the renewal."If they have over a 60-day balance, then it gets flat, then it gets held."Tightened 8/31.
8/06Standup/call transcriptCamellia manager (customer stated)Camellia: a delinquent tenant gets a renewal only after paying in full."as long as he pays everything, then we'll send him a renewal."Became the 8/31 rule.
8/31Claude session a566db0c, 17:51-17:57ZFedeNo renewal outbound to a delinquent tenant; a balance over the policy blocks it whatever the eviction status."this tenant is exxtremely delinquent why did we send that" / "regardless of evicion status the outstanding balance is over the renewal policy right"In force. 10/14: once the customer approves the monthly list, it goes to everyone on it.
8/31Claude session a566db0c, 18:29ZFedeMonth-to-month holdover belongs inside the renewal workflow, not a separate one."i originally wnated the holdover to be attached to the renewal workflow not standalone"Folded into Option B (9/3).
9/03Claude session 28bc997e, 15:04-17:14ZFedeOption B: one renewal engine, one owner; delete the second one."i dont undertadn why there are 2 engines" / "why do we need another engine vs fix wha twe had?" / picked "B — one owner (recommended)" / "i want to never worry about this again"Still in force.
9/03Claude session 28bc997e, 14:36ZFedeTimeouts and system errors alert engineering, never the property team."timeout issues shuld not go to the property team, it should be an alert to engineering"Still in force.
9/04Claude session 28bc997e, 20:28ZFedeRenewals lab: understand each bug, find why the old harness missed it, replay every renewal conversation since launch."phase one here is to be able to cnissitently repdocue in a lab environment. this will include replaying eveyr single renewal conversation / issues weve had since lanuch"Still in force (now the testing ladder, 10/9).
9/04Standup/call transcriptSeanWestern Slope order: maintenance, leasing, then renewals."And then, I think, renewals after that."9/9.
9/09Standup/call transcriptWestern Slope staff (customer stated)Western Slope order: leasing, then renewals, then maintenance."if we're going to focus leasing and then renewals and then maintenance, I think that's fine."Confirmed 9/23.
9/19no raw source found(cited as Fede)"Customers never review; review mode is TEMPORARY." Section J of this page cites it; no transcript, channel post or session line from 9/16-9/22 says it. The word TEMPORARY traces to the 8/30 Camellia bake gate.none foundOverturned 10/8: customers can review.
9/23Standup/call transcriptFedeWestern Slope: renewals come next after leasing."I think renewals make sense."Still in force.
9/30Standup/call transcriptFede, GeraFirst week Supervised: PropFlow reviews each renewal in Slack, within one to two hours."first week it's supervised" / "we review it on Slack, click approve, send it." (Fede); "within the hour to two hours" (Gera)10/8-10/9: the customer reviews too, by email.
10/05Standup/call transcriptFedeNew customer: no renewal phone calls, texts instead."I'm not even gonna try to call people for renewals, because nobody picks up"Still in force (10/12: text on the cadence).
10/05#engineering-bridge (bot relay of Fede)FedeWestern Slope renewals wait for their written policy."Still waiting for the client to tell us the policy"10/7 call gave it.
10/07Standup/call transcriptWestern Slope staff (customer stated)Western Slope policy: 90-day start, 12-month default, renew tenants at a zero balance."Clara opens each renewal 90 days before lease ends, yes. We offer a 12-month" / "I want to renew people at zero."Still in force.
10/07Standup/call transcriptSean, Western Slope staffWestern Slope: no reply converts to month-to-month; the fee is in their lease ($150, was $100)."If they don't reply by the expiration date, it just converts to month-to-month." (Sean)Still in force.
10/07Standup/call transcriptSeanWestern Slope rent: bring renewals up to market."renewal rent, we would just bring it up to market"Same day: flat or $25; 10/12: flat.
10/07Standup/call transcriptFede, Gera (internal call)Start Western Slope simple and Supervised."Not the fully autonomous, fully fancy version." (Fede); "we definitely would want to have some sort of supervised mode right now." (Gera)Still in force.
10/07Standup/call transcriptFedeStep one sends only the messages, not the contract."Step one could be not even send the contract, just send the communication."Still in force.
10/07Standup/call transcriptFedeOne list to the customer: "here are the renewals, review them.""we're gonna renew these people, let us know otherwise." / "these are the renewals, review them."Built as the monthly list (10/9).
10/07Standup/call transcriptFedeWestern Slope rent: flat or +$25."And either call it flat or 25."10/12: flat.
10/08Standup/call transcriptFedeMessages and paperwork are separate; the customer team does paperwork until ready to graduate."we can just do the communications, and then your team does the paperwork, and once you're comfortable, we graduate you to paperwork"Still in force.
10/08Standup/call transcriptGera, FedeSupervised approvals can go to the customer; Supervised is temporary."it could also go to the client" (Gera); "start the supervised mode as soon as possible ... and then eventually we'll not have that." (Fede)Overturns the 9/19 citation.
10/08Standup/call transcriptSeanAssume +$25 for January; go live Monday."we'll just assume a 25 increase for January" / "Monday, we're gonna go live with renewals."10/12: flat, Wednesday.
10/08#engineering-bridge (bot relay of Fede)FedeNew setting "who sends the paperwork", default Clara."'who sends the renewal paperwork: Clara in AppFolio / your team', default Clara, dark."10/12: default is the team.
10/08Claude session f86757cf, 18:59ZFedeWalk Western Slope slowly toward full autonomy, starting Supervised."the customer isn't ready yet for fully autonomous sending out the leases"Still in force.
10/09Standup/call transcriptFedeWestern Slope: Supervised, flat or +$25, the customer reviews by email, approval sends only the messages."They will get an email where they can review" / "Approving sends only the communications and not the paperwork"Rent: 10/12 flat.
10/09#engineering-bridge (bot relay of Fede)FedeOne list email on the 1st of each month; no setting for it."one batch email on the 1st of each month" / "No, I don't, I don't think we want a setting for this." (session 1fcfe5de, 18:54Z)10/13: list review is its own setting.
10/12Standup/call transcriptFede, GeraLevels: messages and reminder texts first, then the customer's own policies, then Clara sends the contract."approve them, and then we'll just text people" ... "the last level is Clara sends a contract for you"Still in force (this page).
10/12Standup/call transcriptFedeWestern Slope go-live moves to Wednesday 10/14."One more day of testing. But by our meeting on Wednesday."Done 10/14.
10/12Claude session 1fcfe5de, 21:55-22:25ZFedePaperwork defaults to the customer team; reviewers live in the customer UI; Western Slope rent flat; only affordable-housing buildings skip renewals."if it's not set like you should default to the team" / "flat" / "yes they are affordable housing"Still in force.
10/13Claude session 1fcfe5de, 19:36ZFedeSupervised (PropFlow checks outbound) is separate from the customer setting "review before it goes out"."the supervise switch has nothing to do with that's just us reviewing the outbounds. But the reviewing the model list, that's a feature in itself."Still in force.
10/14Claude session 1fcfe5de, 16:35-18:09ZFedeReview offers is On by default; the list shows the next 90 days (a setting); an approved list goes to everyone on it."review offers should be on by default" / answered "yes" to "Yes, everyone on the list: they reviewed every row"Still in force.
10/14Standup/call transcriptFedeWestern Slope renewals are ready to turn on in Supervised."Renewals is ready to turn on in supervised mode"Turn-on is Fede's press.
H. Pending inputs and where they land
  • Notifications catalogue: landed as §12-I.
  • Camellia production pass: landed in §9 and §12-K.
  • Design-history timeline: landed as §12-J.
  • Silent decline: issue #19058; engine safety net #19073 ([urgent]) and decline prompt #19075 both merged 10/12 ~23:00Z and deploying. Live proof 10/13 00:01Z on Fairhaven (Fede's phone on the test tenant): the same "moving out" text that produced NOTHING at 20:50Z on the old build now drafts "I'm sorry to see you go… there's a link to file your Notice to Vacate through the resident portal" (held for approval under Supervised, hold eschold_bb01e699; the decline itself was recorded at 20:50Z, intent vacate). Fede on reading it: "What email? … just tell them: here's the link." The wording was the spoken-channel fallback reused on text, and the prompt blanked the portal link whenever the office sends paperwork; fixed in #19126 ([urgent], merged 10/13 00:50Z): the text gives the portal link itself plus the AppFolio "request notice to vacate" hint, or "our office will confirm your move-out date" where no portal exists; voice wording is #19127, no-portal eval #19130. Fede on the no-portal fallback ("our office will confirm your move-out date"): it promised an office action nothing schedules and hands the office work; removed. Open for Fede: at a property with no portal Clara asks the move-out date once and records it herself (draft PR #19151, not merged). Western Slope dry run 10/13 01:40Z, read-only: first list = 16 leases (11 send, 5 held for balance), 0 missing phone or email, every building has a text line, Courtyard and Lincoln explicitly off. Five of the 16 already carry an offer the Western Slope team made in AppFolio; our sync recorded a renewal for each, nothing was sent and no workflow exists. Two fixes in flight: the list treats an existing AppFolio offer as already handled, and the day-before office email lists only renewals Clara started (PRs #19155, #19156). Camellia regression replay 10/13 02:50Z, read-only, real book, tonight's code vs the code before the first merge: 20 leases, decisions identical (4 offers, 1 hold, 15 none), zero texts, emails or AppFolio writes on both; the replay stops before messages are composed, so wording changes are proven by the permutation harness and the Fairhaven run, not by it. Willows: unit decisions identical (33 holds, 2 none), harness crashed on a privacy check of unit labels with spaces on both builds. Western Slope: AppFolio answered 429 on both runs, not retried tonight on a customer account. Permutation harness extended 10/13 03:50Z (PR #19163, test-only, merged 10/13 05:45Z): 48 workflow cells (gate × paperwork sender × 8 tenant replies) + 144 orchestration cells (× portal present/absent) + tool-handler cells; three planted defects each turn the matrix red (48, 97 and 16 cells). Three real bugs under office paperwork, pinned red, fixed in #19166 (merged 10/13 05:05Z): the prompt both forbids and requires quoting the portal link (X-27); the portal sign-in text still sends when the office holds the paperwork (X-28); the offer recap text says "Sign at: " when there is nothing to sign (X-29). Fairhaven live run of the §10 matrix, Supervised, 10/13 03:10Z to 16:45Z on the test tenant with the bench phone only: 7 of 11 cells PASS (yes; moving out with the notice link and no "email" or "office will confirm"; STOP then START; one list email to the reviewer only; approve the list with a rent edit and a skip; reject a list; a 24h-old held reply expires). 4 FAIL, each fixed and merged 10/13 (D1 #19302, D2 #19299, D3 #19300, D4 #19301, D5 #19304), no switch: D1 a reply on an already-escalated thread skipped the hold and went straight out; D2 a roommate who answered was given the offer terms and not named; D3 an opted-out tenant shows as "will send" on the list and approving does nothing; D4 counter-offer: the tenant is told the manager is looped in while no one was told (no property email, and Supervised suppresses the page); D5 (= #18573) a failed approved send alerts nobody and approve reports success. Also seen: START does not undo the email opt-out; the counter-offer first draft is guard-blocked and a vaguer text goes out instead. 10/13 afternoon: offer and reminder texts no longer promise office paperwork before a yes and the Reply YES keyword is gone (#19334, merged); office gets one tenant said yes, please prepare the lease email via the existing notice engine (#19333, merged, D3 yes line shipped); Review offers before sending company setting, on by default, dark (#19337, D2 piece 1); --preview-to on the list send script (#19364, merged) and the real October list sent to Fede only as a gut check: 11 leases, 7 go out, 4 held for balance, 5 left off because the team already offered in AppFolio; no-portal draft #19151 closed on Fede's decision (code bloat); Wednesday flip: Fede will decide later. 10/13 night re-test on main (Fede: do the testing again end to end): regression 465 pass, Supervised permutations 48 cells identical, Camellia replay byte-identical, controls red; Western Slope replay now finishes (#19439) and the 7 send leases match the list, the 4 balance holds are correct (unit 241 balance $1,053 confirmed current by the 5-minute sync; replay gap filed #19443); reviewer-reject cells + recap copy in the suite (#19435; candidate defect #19438 on Clara-paperwork reject re-queue); D2 piece 2 merged (#19440, list honors the setting), piece 3 toggle open for Fede's screenshot ok (#19452). A test inject on the Willows thread exposed two live bugs, both fixed same night with no switch: a phone that exists as a person at several companies resolved to another company's person and fell through to a prospect, so Clara refused the decline tool and improvised (#19460, urgent); a moving-out reply was topic other and not held under Supervised (#19459, classifier 10/10). Willows restored (module off, paperwork sender clara). Wednesday flip: Fede will decide later. 10/14 overnight, Fairhaven live matrix of 17 cases on the test tenant only (bench phone, no Fede contact): 13 pass outright; case 17 passes on the redo via the real inbound path; the 3 remaining defects were fixed and merged the same night, no switch, and are being re-proven live this morning: a roommate who texts no longer renames the tenant (Clara keeps greeting the tenant by their own name, the third party's name is kept on the escalation, #19497); the "tenant said yes, please prepare the lease" office email is held in the renewal queue while Renewals is Supervised instead of sending at once (#19492; card wording follow-up #19496); the hallucination guard no longer replaces Clara's correct decline of a counter-offer with the canned "I've noted your request" (#19498: a tenant-stated amount is allowed only when the escalate tool actually ran that turn, no term-changing tool ran, and the wording refuses or merely records the number; five rounds with the review bot, closed on the bot's own structural rule; issue #19494). Also merged overnight: no bare "Hi," in the list email (#19409), replay harness subset env and privacy fix (#19439), reviewer-reject cells + recap copy pins (#19435), list honors the review setting (#19440, D2 piece 2), move-out reply classified as a renewal topic and held (#19459), tenant lookup scoped to the dialed property's company (#19460, urgent). Open: toggle UI #19452 (D2 piece 3, dark, waits for Fede's screenshot ok); issues #19438, #19443, #19494 (decision A implemented), #19496. Production at 06:42Z 10/14: Lambdas and renewal worker both on main d8fc1ca99 with all of the above. 10/14 morning re-proof on Fairhaven at d8fc1ca99 (test tenant, bench phone only): counter-offer decline goes out held and not canned (PASS), questions get real answers held (PASS), the office "said yes" email is held under Supervised and owned by Renewals (PASS), roommate case half: name saved and nothing leaks, but the tenant's next unsigned text was still treated as the roommate. Two defects found and fixed the same morning, no switch, both merged: an unsigned text after a roommate speaks is the tenant again (#19569: two contradictory prompt lines, the older one deleted); the office "said yes" email quoted the pre-edit rent ($2,395) instead of the rent the reviewer approved on the list ($2,450), because it read the saga's frozen snapshot instead of the lease's prepared offer (#19570, regression X-36). Follow-ups: #19571 (note omits a reviewer-added concession), #19572 (recap text derives rent from market rent). Nothing reached Fede's phone or mailboxes; Fairhaven left clean, only the James workflow running.
PropFlow Docs