Renewals with the team in the loop

Western Slope decides renewals in a weekly meeting and carries them out by hand inside AppFolio.C42 C48 This design lets Clara prepare those decisions, confirm them and carry them out, until the team reviews only the exceptions.

2026-10-15, updated 2026-10-19 (section 10: offers through AppFolio, supervised) and 2026-10-20 (11: why so much built, packet-first; 12: simplify-first pictures for Oct 21) · Proposed — pending review · lane 007 · builds on Renewals, end to end: levels of autonomy · each C# mark links to its row in the claims register

1 TL;DR 2 Current state 3 Architecture 4 Decisions 5 Slices 6 Tuesday 10/20 7 Proof 8 Open questions 9 Engineering notes 10 Update Oct 19: through AppFolio, supervised 11 Update Oct 20: why so much built, packet-first turn-on 12 Oct 21 meeting: simplify first 13 Oct 21: the document engine 14 Nov 3: leak audit

1 · TL;DR

Short version: /a/renewals-overnight-brief-2026-10-16

Western Slope's renewal emails and texts all go out inside AppFolio, where PropFlow sees almost none of them: our record disagrees with their Monday board on 17 of 32 leases, and the ten January price emails sent on Oct 13 are nowhere in PropFlow.C1 C6 C12 C49 The design is one weekly loop: Clara sends a pre-read, the team decides by reply or in their meeting, Clara emails back exactly what will go out, and one approval hands it to the same renewal engine.C42 C43 Two guards: Clara never messages a tenant a teammate already reached out to, a fact checked before every message and never a setting, and nothing goes out that the team did not see in the confirmation.C42 C50 Customers can approve every week or let Clara run; the end state is Fede's: no meeting, no approval, the team reviews only the exceptions.C41 C42 Asks: four decisions in section 4 (D5 is approved and in progress) and a go on slices 1, 2, 3 and 6, which ship with no switch; slices 4 and 5 are new and ship dark.

Before → after, and the full design (sections 2 to 9)
Before → afterTodayTarget, after slices 1 to 6
Leases where PropFlow and their board disagree17 of 32 C120: the weekly pre-read becomes the board
What PropFlow knows went outAppFolio offers only, and only while no Clara renewal is open C10 C57AppFolio offers, texts and emails, each dated
Renewal messages checked for a teammate's touchNone: the only check is Supervised review C35 C27Every one, in every mode
What an approval sendsEverything on the list, within seconds C53 C26Exactly what the confirmation listed
RhythmA monthly list C33The company's own day and time

Fede's mental model (2026-10-15)

Rule 1 (Fede, verbatim): "if a renewal is already sent, or a team mate already reached out, we skip that one." Confirmed: "yes. if a human starts it we don't intervene." Clara skips that lease for the cycle: no offer, no reminders; she still answers a tenant who writes to her, and the row shows "skipped: team has it" on the pre-read. This replaces the earlier "hold, then resume on her interval from the staff touch" in slice 1.

Rule 2 (Fede, verbatim): "temporal is the 'alarm clock' that wakes up Clara. Clara should check the state of the world and what has been done by teammates already, and reason if we should send the follow up or not." The workflow timer only wakes Clara; nothing is sent from a stale plan. Fede: "at the minimum it should check if another staff member replied before blindly sending a copy paste follow up"; "come up with a simple solution"; "design this very carefully, like we are doing with guest cards"; and the existing send-time gate stays where it is ("that's a minor nit"; "most of the time staff didn't intervene is a good assumption"). Today the workflow checks only Clara's own channels at each reminder (a tenant reply to Clara, a signature, a notice, a manager decision); staff messages, tenant replies inside AppFolio and a contract going out do not stop it, and renewals do not call the staff-touch gate at all.

The simple version: two reads, three rows

At each wake, before any scheduled messageClara doesHarness case
1 · A human has messaged this tenant since Clara's last message (our threads plus AppFolio history)Skip the lease for the cycle (rule 1); answer only if the tenant writes to herFirst case: Pomona Park 305, Bev's Oct 6 text
2 · A contract is out or signed in AppFolio, or the tenant replied on any channelStop reminders; answer questions onlyColorado Ave unit B: yes on Sep 28, contract Oct 6
3 · NeitherSend the scheduled messageA December row with no staff text
A read failed or is staleDo not send this wake; retry at the next; hand off after threePlanted: the picture read times out

Shared piece: the staff-touch reader is one module-neutral function on the person picture (Lead Intelligence extracts it from the existing follow-up gate, prospects byte-identical; a second small PR lets the picture take PMS conversation rows in the neutral shape). Renewals, prospects and maintenance call the same function; Smith is told on the bridge when it opens. Gets the guest-card treatment: this design section first, a replay harness over the real December and January rows with the verdict and evidence per lease, planted-defect controls; nothing sends from a wake until the harness is green.

Timeline of one renewal (Fede, 2026-10-15: "clara starts earlier")

flowchart LR
  A["1 · Clara first\noffer · questions · yes or no\n(90 days out)"] --> B["2 · Clara tells the office\nthe tenant said yes"]
  B --> C["3 · Office sends the contract\nin AppFolio (any time,\nalso on their own)"]
  C --> D["4 · AppFolio's reminders\ncarry the document\n(day 1, 2, 7)"]
  C -. the sync records it;\nClara's reminders stop,\nshe only answers .-> A

Clara's conversation comes before any AppFolio contract; AppFolio's automatic emails start only when the office sends the contract, which is the hand-off point. Verified on one Western Slope lease: the office's price email in August, a nudge text a week later, the tenant's yes at the end of September, the AppFolio offer on Oct 6 and its reminders on Oct 7, 8 and 13 C48. Staff can do any step by hand at any time; Clara detects it and adapts, never a process agreement (D1).

2 · Current state

One November lease, as AppFolio recorded it, next to what PropFlow saw.C48 C10 Their steps are a reference for mapping, not our spec.

flowchart LR
  subgraph WS["Western Slope today: one November lease, from its AppFolio record"]
    direction TB
    a1["Aug 11 · price heads-up\nemail from the shared\nAssistant PM login"] --> a2["Aug 18 · nudge text"]
    a2 --> a3["September\ntexts both ways"]
    a3 --> a4["Sep 28 and 29\ntenant: yes\nstaff: I'll let Kat know"]
    a4 --> a5["Oct 6 · the office creates\nthe AppFolio offer"]
    a5 --> a6["Oct 7, 8, 13 · AppFolio's\nown reminder emails"]
    a6 --> a7["next: e-sign in AppFolio"]
  end
  subgraph PF["What PropFlow saw"]
    direction TB
    p1["nothing until\nthe AppFolio offer"] --> p2["board: waiting,\nwith an Offer sent dot"]
  end
  MB["Monday board\nupdated by hand"]
  a4 -.-> MB
  a5 -.-> p1
Every touch happened inside AppFolio, and the board is kept by hand.C48 C12 PropFlow saw only the AppFolio offer.C10 C25
17 of 32
leases where PropFlow disagrees with their Monday board C12
10 of 10
January leases sent a renewal price email on Oct 13; PropFlow records none C49
0 of 1,832
renewal offer emails in their leasing mailbox C20
0 of 1,871
AppFolio messages our robot read that are emails C5
PieceToday
Their renewal messagesBev's price emails from the shared Assistant PM login, with open tracking, AppFolio's own offer email and reminders, and texts, all inside AppFolio; tenants' email replies land there too C1 C22 C2 C3 C48
What PropFlow sees of themOnly the AppFolio offer, through the sync (our scheduled AppFolio pull): the board shows "waiting" with an "Offer sent" dot C10 C25. Nothing reads AppFolio email C11 C23; the robot (our browser agent for AppFolio) reads texts only C5 C24
The inbox mirror (our copy of AppFolio's texting inbox)On only at Willows, leasing only; tenant threads are out until Fede rules; Clara never wakes on a mirrored row C7 C44
Renewals at Western SlopeOff C8; 32 leases end November to February C9; the tenant sync has not run since Sep 9 C18
The list (today's pre-read)One per month per company, never weekly C33; it opens only when a building is Supervised (Clara's messages held for review) and "Review offers before sending" is on, its default C34
Starting a renewalSkips only when an offer is already prepared or open in AppFolio; a staff price email or text never counts C45
"A teammate already reached out"No general check; code read, the planted case is not yet verified C14. The one stamp is set only by a manager's email reply at a property whose delivery mode is AppFolio, and none of 159 is C27; renewal emails never read it C29
A check before each messageOnly the Supervised check C35. A "check before send" stage was option (a) on 10/12 and was not chosen C40
Clara's reminders vs AppFolio'sClara's stop on a tenant answer, a signature, a notice or a manager decision, not when the office creates the AppFolio offer C36; AppFolio then sends its own three C2. While Clara's renewal is open, the sync drops a new AppFolio offer with a log line C57
A held messageWaits 24 hours, then expires: the reminders stop and the manager is paged. Only a message parked on an unapproved list waits longer C52
Meeting notesForwarded notes are on at Western Slope; the video join is built and off C15; no invite has arrived C16
Clara reading notesStored, never read: two writers, no reader C17

3 · Full architecture

One loop, every week. The weekly review is one more alarm into the same loop, with the pre-read and the meeting notes as picture inputs.C50 The person picture is PropFlow's one record of what it knows about a person; an alarm is a timed wake-up that makes Clara look before she acts.C46 Renewals reuse the lead lane's person picture, its alarm seam and its four rules; moving the renewal timers onto that seam is a later migration.C46 C50

flowchart TB
  AL(["Weekly alarm\nthe company's day and time"])
  AF[("AppFolio\ntheir source of truth")]
  PIC["Person picture\nmessages · notes · owner\nrecord changes\nwhat was sent"]
  PRE["① Pre-read email\nto decide · what changed\nwhat goes out next"]
  TEAM{"② The team\ndecides"}
  RE["a reply to\nthe pre-read"]
  MT["notes emailed to us"]
  NT["Clara as note taker\nor on the video call"]
  VC["a phone call,\nor any other text"]
  DE["One decision engine\nsource-agnostic: text in,\nper-lease decisions out,\neach with its quote and source"]
  BR[("Company brain\nprivate, staff only")]
  CF["③ Confirmation email\nonly for meeting inputs\nor when Clara is unsure"]
  EN["④ Renewal engine\nthe same in every mode"]
  CK{{"Staff-touch check\nbefore every message"}}
  DR["⑤ Send\nthrough AppFolio once\nthe door is ready"]
  HD["held, listed in\nthe next pre-read"]
  AL --> PIC
  AF -- "sync and mirror" --> PIC
  PIC --> PRE
  PRE --> TEAM
  TEAM --> RE
  TEAM --> MT
  TEAM --> NT
  TEAM --> VC
  RE --> DE
  MT --> DE
  NT --> DE
  VC --> DE
  MT -.-> BR
  NT -.-> BR
  VC -.-> BR
  DE -- "typed reply: sends as today" --> EN
  DE -- "meeting input, or unsure" --> CF
  CF -- "approve" --> EN
  EN --> CK
  CK -- "clear" --> DR
  DR --> AF
  CK -- "a teammate is on it" --> HD
  HD -.-> PRE
The weekly loop. Their words: "getting that on Tuesday morning, and then using that as our fodder for the meeting".C41 After ③ the engine is the same in every mode. No new screen and no new email template: the pre-read and the confirmation reuse the list's renderer and the coworker email standard.
LayerWhat it doesBuilt todayNew
① Pre-readThe list email on the company's day: leases ending in the next 90 days with the default policy and balances, what changed since last week, what goes out next. It replaces the Monday board over time; they keep the board until they don't need it C43 C41A monthly list C33Weekly: a new capability (slice 4)
② Any text, one engine (Fede, 2026-10-15: "N doesn't matter the source, it's just text… could even be a phone call… agnostic")A reply to the pre-read, notes emailed to us, Clara as note taker or on the video call, a phone call transcript: examples, not a list. One source-agnostic decision engine: text in, per-lease decisions out, each with the quote it came from and its source. No per-source readers. The raw input is kept in the company brain C42The reply reader C37; notes stored, never read C17; the note reader is a prototype C19The one engine (slice 5): Fede's go 2026-10-15, "build and battle test that layer"
③ ConfirmationSame list email, re-rendered with the decisions applied. Sent only when the decision came from a meeting input (nobody typed it) or Clara is unsure; a typed reply is its own confirmation and sends as today (Fede, 2026-10-15). A wrong confirmation is fixed by reply; after three rounds on a row it shows "needs you" on the page, never a send C42No: today an approval sends at once C53Slice 2
④ EngineUnchanged: one renewal per lease; the offer, reminders on day 2 and day 9 by default, answers, the hand-off to the office C36 C30. At Western Slope, month-to-month handling and Clara sending the contract stay off C43 C55Built C36Nothing
⑤ AppFolio doorClara's messages go inside AppFolio, as staff's doThe text door: one company switch, off by default; it needs the tenant's thread in the mirror, or the text is held C38. No AppFolio email send C23Tenant threads and a first text with no thread (AppFolio Communications lane); one door for everything later (slice 10)
"What was sent" readsKnow what already went out, by channel, before Clara sendsThe AppFolio offer, while no Clara renewal is open C10 C57Slice 6, with the reads in the next figure C56
Staff-touch ruleBefore any renewal message: since Clara's last message, did a teammate write, add a note or take ownership, or did the record change? Then hold. A fact derived from the picture, never a setting C50No general check; planted case not yet verified C14A fix, no switch (slice 1)
Company brainPrivate notes. Clara reads them only for staff-facing work (the confirmation, the terms), never inside a tenant messageThe store; no reader C17One staff-only reader (slice 5)
Tenant history, laterWork orders, complaints and payments as fields on the same picture, shown as flags in the pre-read: "consider not renewing", "consider a concession". No second store C42 C50NoLater (slice 7)

What was sent in AppFolio, in one place

flowchart LR
  SY["The sync\nthe AppFolio offer,\nnotice, signature"] --> V
  LI["Per-person history read\ntexts and emails mixed\nrobot route, live (D5)"] --> V
  HI["Per-number history\ntexts, once tenant\nthreads are mirrored"] --> V
  GC["Guest-card read\nprospects only"] --> V
  V["What was sent in AppFolio\non the person picture,\neach item dated"] --> U["the staff-touch check\nand the pre-read"]
Three reads plus the sync. AppFolio's own inbox shows a tenant's texts and emails in one timeline.C4 The probe on 2026-10-15 showed the inbox list ignores the email flag: 20 rows with or without it, byte-identical, and an empty list with texts off.C58 Emails come back only from AppFolio's per-person history, keyed by the person's record, texts and emails mixed; the robot reads it today for prospects only, and the new route reads it for tenants, proven on 2026-10-15 (D5).C59 C56 C31 C58

The staff-touch check

flowchart LR
  due["A renewal message is due\noffer · reminder · nudge"] --> pic["Read the person picture\nstored by the sync\nand the mirror\nno AppFolio call\nat send time"]
  pic --> q{{"Since Clara's last message\na teammate wrote, added\na note, took ownership,\nor the record changed?"}}
  q -- "yes" --> hold["held with the reason,\nparked for the\nnext pre-read"]
  q -- "no" --> mode{"mode"}
  mode -- "Supervised" --> list["list check,\nthen send"]
  mode -- "Live" --> send["send"]
  pic -- "cannot read" --> retry["wait and re-check\nnever a blind send"]
The check runs first, in every mode, inside the step every renewal message already passes, so running renewals need no change.C35 It reads only what is stored, never AppFolio.C51 At Western Slope Bev's texts reach the picture once tenant threads are mirrored, her emails once the list read is on;C44 C56 until then the team's review of the pre-read is the guard.

The decision engine over time

flowchart LR
  L1["Level 1\nthe team decides,\nthe office sends\nthe paperwork"] --> L2["Level 2\nClara also sends\nthe paperwork,\nonce templates exist"]
  L2 --> L3["Level 3\nClara decides by policy,\nthe list optional"]
  L3 --> L4["Level 4\nplus the team's\ninternal notes"]
  L4 --> L5["Level 5, proposed\nexceptions only\nhistory and market\nas inputs\nno meeting, no approval\ncontract included\nflagged rows to the team"]
Levels 1 to 4 are the autonomy page's; Camellia is at level 3 today.C40 Level 5 is Fede's end state.C42 Western Slope stays at level 1 with weekly approval: "Certainly at this stage, I would want a human to review."C41
Input to the engineWhere it comes fromWhen
Policy: rent rule, eligibility, who sends the paperworkCompany and building settings C40 C55Today
The team's decisionsTheir reply or their meetingSlices 2 and 5
What already happened: offers, replies, teammate touchesAppFolio, through the sync, the mirror and the robot's readsSlices 1 and 6
Tenant history: work orders, complaints, paymentsAppFolio, as fields on the picture; the tenant page already holds it C48Later
Market: vacancy, comparable rents, similar vacant unitsTheir own portfolio C42Later

4 · Decisions for Fede

flowchart TB
  subgraph T["Today, if the office creates the AppFolio offer while Clara is still reminding"]
    direction LR
    o1["office creates\nthe AppFolio offer"] --> o2["AppFolio: offer email,\nreminders day 1, 2, 7"]
    c1["Clara: offer text"] --> c2["Clara: reminders\nday 2 and day 9"]
  end
  subgraph B["Recommended D1 (b): one cadence at a time"]
    direction LR
    b1["Clara: offer text,\nreminders, answers"] --> b2["tenant says yes,\nClara stops"]
    b2 --> b3["office creates\nthe AppFolio offer"]
    b3 --> b4["AppFolio: offer email,\nreminders, e-sign"]
  end
  T ~~~ B
Two cadences. AppFolio's offer email and reminders are verified on a Western Slope lease;C2 Clara's reminders stop on a yes, not on a new AppFolio offer.C36
DecisionOptionsRecommendation
D1One cadence or two(a) Clara's texts run alongside AppFolio's emails, and her reminders stop when AppFolio's start: a change to the running renewals · (b) the office creates the AppFolio offer only after the tenant says yes to Clara; Clara's reminders already stop on a yes C36 · (c) the AppFolio offer is the offer from day one and Clara only follows up: every offer built up front, and a change to Clara's reminders(b): one cadence at a time, no change to running renewals, and it matches their own two-step process C48. If the office creates an offer early anyway, slices 6 and 1 record it and hold Clara's next reminder.
D2Closed as moot (Fede, 2026-10-15: "this is for supervised mode"). The 24-hour expiry applies only to a Supervised-mode hold outside a list; a row parked on the team's list never expires, so the team's rows have no timer and nothing changes. Remaining edge, handled in slice 3: a lease that opens after the month's list gets a 24-hour hold instead of a row; it should join the next list. Original question: What happens to a message the staff-touch check stops(a) It waits on the lease's row in the next pre-read until the team says "go" or "we have it"; at a company with no list, Clara stands down for the cycle and the board shows "needs you". Both reuse built pieces that page no one C52 · (b) Clara skips that message, re-checks at the next one and resumes after 7 quiet days: a new timer · (c) Clara stands down for the cycle everywhere(a): the people who touched the tenant decide, in a meeting they already hold. The replay of Camellia's book counts the stand-downs before it ships. Never today's plain 24-hour hold, which stops the reminders and pages the manager when it expires C52.
D3Fede's end state as a level(a) Add level 5, exceptions only, above the autonomy page's four; a level is a preset of settings, not a new switch C40. A company moves up only on Fede's press, after a run of confirmations approved with no edits · (b) no new level: level 3 with flags in the pre-read is the end state(a): it makes the 80/20 measurable C42. Built later (slice 9).
D4Collapsed (Fede, 2026-10-15: "isn't it the same engine?"). Any text that arrives Tuesday goes through the one engine; the engine ships when its battle test is green and Fede's dry runs look right, not by the calendar. Left for later: which door brings meeting text in on its own (forwarded email or a bot in the meeting). Original question: First input to prove at Western Slope(a) Their reply to the pre-read, since the reply reader is built C37; notes are stored from day one, and the note reader follows after its replays and a Fairhaven run · (b) the meeting notes first, as the 10/20 plan said C43: the note reader goes live by Tuesday, before its Fairhaven run · (c) both at once(a): proven pieces first; the note reader is new and climbs the ladder (slice 5).
D5Read a tenant's AppFolio emails and texts. Approved by Fede 2026-10-15 ("emails and texts are fair game for the conversation"); owner: the AppFolio Communications session; merged and proven as appfolio-browser-agent PR #532 (one request per person, texts, email and chat, warm session only). Production probe 2026-10-15, one request, no login: tenants come back; one Western Slope tenant returned 20 rows, 14 texts both ways and 6 outbound emails, rows typed by channel, with a per-channel cursor. Still unverified: applicant and occupancy parties, and the cursor boundary C59(a) A new read-only robot route: the per-person history AppFolio keeps per record, texts and emails mixed, which the robot already reads for prospects; run it only for tenants with a renewal in the next 90 days, inside the sync's budget · (b) Keep emails out: PropFlow knows texts and the AppFolio offer only, and the team strikes emailed leases in their reply, as the Tuesday cut has it C58 C31(a): Fede said all communications; without it the staff-touch check is blind to Bev's price emails, which is how every Western Slope renewal starts C1. Read-only, Gera's robot, scope ≈ one route plus a sync step; tenants on that endpoint are unverified until the first probe.

5 · Slices

In execution order. A fix ships with no switch, live everywhere, and stops at the Willows rung; a new capability ships dark as a company setting and climbs to Fairhaven before Fede turns it on. Rungs, from the testing playbook: 1 unit test with a planted defect · 2 replay of every live customer's real book · 3 workflow history replay · 4 Willows live · 5 Fairhaven · 6 supervised week. Sizes are estimates.

flowchart LR
  S6["6 · what was sent\nin AppFolio · fix"] --> S1["1 · staff-touch check\nyes, Fede 10/15 · before the WS flip"]
  S5["5 · one decision engine\nFede: build and battle test"] --> S2["2 · confirmation, meeting\ninputs only · improvement"]
  S2 --> S4["4 · weekly pre-read\nnew, dark"]
  S3["3 · list on its own\nsetting · fix"] --> S4
  IP["in progress\ninbox list read,\nall channels"] --> S6
  X["AppFolio Communications lane\ntenant threads · first text\nwith no thread · failed writes"] -.-> S6
Order after Fede's pass (2026-10-15): slice 5 first and alone, built and battle-tested before any other slice, with a dry-run mode he runs himself from pasted notes (nothing sent, nothing written to a customer record); then 2, 3, 6; slice 1 later. 4 ships dark; 6 grows as the reads land.
#SliceFix or new · switchRungsProof (the planted defect must go red)SizeUnblocks
1Fede yes, 2026-10-15: built before the Western Slope flip, after the interface chain and slice 6; fix, no switch, full ladder. The hold skips only Clara's own scheduled message, never a reply; she resumes on her usual interval counted from the staff touch. Staff-touch check before every renewal offer, reminder and nudge, in every mode. Window: since Clara's last message, or since the cycle opened. Reads the picture only; an unreadable picture retries three times, then holds C35 C50 C51Fix · no switch1 2 4 (no workflow change)Willows: a teammate texts the bench tenant from PropFlow; the due reminder holds with its reason. Planted: skip the check and the reminder sends. Camellia's book: every changed send is a lease a teammate touched; the rest byte-identical~250Clara at Western Slope without talking over a teammate
2Confirmation email after a reply, then after a meeting; one approval releases exactly what it lists C42Improvement to the list review · no switch1 2 5*Fairhaven: reply with edits; the confirmation shows the exact texts; approve; texts reach bench phones only. Planted: a lease changed after the confirmation still sends~250The guard for both inputs
3The list rides on "Review offers before sending", not on Supervised, as decided 10/13; a data step first writes "off" for every company on Live today C40 C34Fix · no switch1 2 5*Camellia's book byte-identical; Fairhaven in Live with the setting on still gets its list. Planted: a Live building skipped~150 + data stepWestern Slope keeps its review after it moves to Live, planned from about 10/21 C40
4Weekly pre-read and confirmation on the company's day and time; the list becomes one per company-week, so leases that open mid-month wait on next week's list instead of a 24-hour hold C33 C40 C52New · Dark: renewal.weeklyReview | feature: the renewal pre-read and confirmation run weekly on the company's chosen day and time | proof: pending | turn-on: Fede1 2 3 5 6Fairhaven gets the pre-read at the set time, with last week's changes. Planted: a lease decided last week shows as newtwo PRs, ~250 eachThe Tuesday rhythm without us
5One source-agnostic decision engine (Fede's go, 2026-10-15, "first"): any text in (a reply, emailed notes, a note taker, a video call, a phone call); per-lease decisions out with exact quotes, who said them and the source, stored on the list's per-lease rows (latest wins, history kept); the reply reader becomes one caller of it; a dry-run mode for Fede: paste notes, get the decisions, nothing sent or written; an unknown unit, a contradiction or a loose instruction becomes a question; one staff-only reader added to the two files allowed to touch private notes C19 C17New · Dark: renewal.meetingNotesDecisions | feature: Clara turns the team's meeting notes into renewal decisions for them to confirm | proof: pending | turn-on: Fede1 2 5 6Battle test: the 7 prototype cases, the 10/14 meeting, the real Western Slope reply and notes on record, plus the never-run cases: a transcript pasted into a reply, a fresh email with pasted notes, partial notes, contradictions, loose "next week" lines; controls G1 to G6 red; then the Fairhaven run. Dark, no customer send. Planted: an invented quote; the demo line read as a decision~300The meeting input
6Re-cut by Fede 2026-10-15: AppFolio's own offer emails and reminders are ignored (the client turns them off; D1's one cadence). Kept, later: the messages staff typed to a tenant in AppFolio and the tenant's replies, pulled from the per-person history read onto the tenant's record and timeline, written against a PMS-neutral row shape. Original cut: What was sent in AppFolio, on the picture, each item dated: record the AppFolio offer on the open renewal instead of dropping it; texts from per-number history once tenant threads are mirrored; emails and texts from the per-person history read, live since 2026-10-15; a bulk renewal text counts as an offer here, never as a teammate touch for leads C57 C56 C46Fix · no switch1 2 4Willows: create the AppFolio offer on the bench lease while Clara's renewal is open; it appears dated and Clara's next reminder holds. Planted: the sync drops it, as today~150, then small steps as the reads landThe pre-read's "already sent" column; D1's safety net
In progressThe robot's inbox list read takes channel switches (texts, email, chat), default unchanged; the read-only probe ran on 2026-10-15 against the deployed robot (5 requests, nothing written). Verdict: the list endpoint ignores email; the switch stays useful for chat and the mirror. Approved by Fede 2026-10-15; owner: the AppFolio Communications session C24 C56Read-only robot change · no settingprobeVerified in code: the list read asks for texts only today, and the guest-card read already asks for email C24 C31. Probe result: no email row exists on the list endpoint. Emails live on the per-person history; see D5smallChat rows in slice 6; emails wait on D5
Later7 tenant-history flags in the pre-read · 8 market inputs and a proposed price per row · 9 level 5, exceptions only, after D3 · 10 one setting that sends everything through AppFolio C42 C437 and 8 ride the pre-read's setting · 9: Dark: renewal.reviewExceptionsOnly | feature: the team reviews only flagged rows; Clara sends the rest by policy | proof: pending | turn-on: Fede · 10: Dark: pms.allDoors | feature: every Clara message to this company's tenants goes through AppFolio | proof: pending | turn-on: Fede1 to 6Each with its own planted defect≤300 eachFede's end state

* The list is company-level, so Fairhaven, in Western Slope's shape and where the list already runs, is the live rung for slices 2 and 3.C53 The setting keys in the Dark lines are proposed names.

Owned by the AppFolio Communications lane, not this page: tenant threads in the mirror (Fede's ruling), the first renewal text to a tenant with no AppFolio thread, when Clara answers on a mirrored thread (their section 8c, proposed), and the queue and alerting for failed AppFolio writes (their section 8d, pending).C44 C38

6 · Tuesday 2026-10-20 cut

Dry runs first (Fede, 2026-10-15)

Fede: "ideally what we ship is either Clara as a coworker joins (video or audio) and takes notes, saves them in private company brain raw. I'll take raw notes too. Then we will do a dry run and test that" · "we do that a couple times" · "I'm sure there will be bugs" · "make it as production ready as possible but realistically things never work the first time". The engine is built to production standard (full ladder); the dry runs are the real-world check on top, never a reason to lower the bar. Nothing goes to a tenant in this phase.

flowchart LR
  M1["Tue Oct 20\nWS renewals meeting"] --> N1["Clara's raw notes\n(join, or notes forwarded\nto clara@) → private brain"]
  M1 --> N2["Fede's raw notes"]
  N1 --> E["One engine · dry run\nread-only, nothing sent"]
  N2 --> E
  E --> C["Compare: Fede's notes\nvs Clara's vs engine output"]
  C --> B["Every miss → a case\nin the battle test"]
  B --> M2["Tue Oct 27: again\n(more if needed)"]
  M2 --> F["Then, Fede's press:\nRenewals at WS → Supervised"]

Clara in the room: a one-time invite to clara@ from a Western Slope organizer (recurring series are skipped, our own domain is refused) plus Fede's press on the meeting-join setting; the video Clara has a 15-minute call cap and no rejoin, so a forward of the notes or transcript to clara@ after the meeting (already on at Western Slope, proven Oct 10) is the reliable path for the first runs. Her notes land in the private brain today on both paths; nothing reads them until the engine does.

Switches Fede can press todayCode that needs a go or a decision firstManual fallback
Renewals at Western Slope: off to Supervised C8 · "Review offers before sending" is on unless set off, so the list opens; their stored value is not yet verified C34 · who sends the paperwork: unset means their team, so Clara creates no AppFolio offer and sends no contract C55 · the AppFolio text switch stays off for now: it needs the tenant's thread in the mirror, and tenant threads wait on Fede's ruling in the AppFolio Communications lane, so today it would hold every renewal text (superseded 2026-10-19: section 10, decision D7, a renewals-only scope on the door) C38 C44 · the video join stays off: as built it skips recurring invites and ends a call at 15 minutes C15 C28 Slices 1, 2, 3 and 6: a go · slices 4 and 5: dark, Fede's turn-on later · D1 and D2 shape slice 1 and the office's timing · the inbox list read is merged and probed; a tenant's emails need D5 C58 The team answers the list by reply; the reply reader is built C37 · notes reach the company brain by forwarding C15 C17 · approved texts go from Clara's own line, as the 10/12 plan had them, until the AppFolio door works for tenants C40 C38 · January went out by email on Oct 13 and PropFlow knows nothing of it C49 C45: the team strikes those leases in their reply, because nothing else stops a second offer before slices 1 and 6 · until slice 2, an approval sends at once with no confirmation C53 C40

Details: section 9.3.

7 · Proof

Every result shows its planted control going red; a check with no control does not count.

TestCasesResultPlanted controls, all red
Meeting transcript to per-lease decisions: the renewals part of the 10/14 meeting plus six edited variants, 3 runs each, on the subscriptionreal · (a) a unit named twice · (b), (b2) a contradiction · (c) a unit not on the list · (d), (d2) one global instruction21 of 21 runs green: every row right, 0 invented quotes, 455 of 455 quotes found in the transcript, the same answer on every repeat; about 18 s a run. Re-run 2026-10-15 C19 C54G1 an invented quote · G2 the demo line read as a decision · G3 an unknown unit put on another row · G4 picking a side of the contradiction · G5 a global instruction not applied · G6, added for this page: guessing which unit 4 with no question C19 C54
What broke(b)The grader, once: the fixture missed that "the rest we can figure out next week" is a real hold. A real quote is not proof: G2 passes the quote check, and only the expected-answer check catches it C19Controls test the grader too
ClaimEvidenceRow
Their renewal offers also go out as AppFolio texts2 of 8 December units carry a bulk offer text (Sep 28, Oct 6), in a read-only capture of their texting inboxC6
The robot's thread history is texts only1,871 messages and 433 list rows, 0 emailsC5
Price email, AppFolio's offer and its reminders are all inside AppFolioOne tenant's Emails panel and its exportsC1 C2 C48
Their leasing mailbox sees none of it1,832 messages, 0 renewal offer emailsC20
PropFlow vs their board17 of 32 rows disagree; January emailed Oct 13, December Sep 1C12 C49
An approval sends fastThree Fairhaven list approvals sent the offer text 18 to 26 s later, one of them by email replyC53
The tenant sync is stale0 runs since Sep 9C18
Not yet proven: the planted teammate-text caseWritten for Fairhaven, not runC14
Proven: "do not contact" from the reviewer parks the row and revokes renewal outreach (Willows sandbox, 2026-10-16)November list eschold_rb_4188a542e1f457ad4b6ea6a1 opened early; a genuine reply naming the unit parked its row (skipped, reason do_not_contact, reply quoted) and wrote two renewal_outreach suppressions (supp_46a9154f-d834-4fda-a2f2-7dba00640608, supp_8ca67a70-6266-4366-a5fd-8311dcf44f3d); the send check blocks renewal outreach and still allows replies to the tenant's own messages; the other row on the building stayed released—
Proven: a STOP blocks the renewal offer (Willows sandbox, 2026-10-16)Opt-out supp_a9e65c52-edb2-4623-8cd7-024ec459c656 recorded 07:49Z; at the 14:00Z window the offer email ended failed "refused:opted_out" on lease lease-yale-sandbox-stop-proof-01, 0 messages to the bench address—
Proven: a parked hold released by approval (Willows sandbox, 2026-10-16)Held text eschold_rt_b4c24c3e3c9448285c27fadf parked on list eschold_rb_4d0ab592c96791e698e91465 at 14:00Z; one approval by the test reviewer at 14:10Z released the offer text (eschold_rt_9b1961d447262d8d746f507e) with no second press; the send ended dispatched_failed to the fake number, as seededC32 C13
Disproven: an email row from the inbox listProbe 2026-10-15: email flag ignored (byte-identical 20 rows), chat flag honored (19 texts + 1 chat), texts off gives an empty listC58
Proven: the PMS adapter chain reads a saved copy, never AppFolio live (#20404, #20408)Production, 2026-10-16 10:21Z, first poller run after the deploy: a saved renewal-state record per property; three read-only reads (41, 6 and 16 rows) match the replay row counts exactly, every row id provider-prefixed; the replay stayed byte-identical and a planted dropped row goes red in three places—
Proven: a tenant's emails and texts from the per-person history routeProduction probe after #532 merged: 20 rows for one tenant, 6 of them emails, typed by channelC59

7.1 · Production battle test: the reply reader at Fairhaven, 2026-10-16

We sent 14 real reviewer email replies to the October renewal list at Fairhaven, our test company. Every step ran on production between 07:23 and 07:36 UTC.

Before: reader proven only on replays; after: 14 real reviewer replies on production, 0 non-test contacts reached, 6 defects found.

StepReplyWhat Clara didResult
L01From a strangerRefused it and alerted the teamPASS
L02Asks how to replySent the how-to linePASS
L03A questionAnswered the questionPASS
L04Unit 305 rent to 2,645Recorded itPASS
L05Corrects unit 305Read "Actually" as a name; no correctionFAIL
L06Concession for unit 101Recorded itPASS
L07Six-month term for unit 4Recorded itPASS
L08Month to month for unit 1254Recorded it directly, no question neededPASS (better than expected)
L09Ambiguous leaseAsked which lease, but listed struck unit 2PASS, with defect
L10Do not contact unit 13Recorded the skip, kept the rowPASS (better than expected)
L11Unit 1460-1, not on the listMapped it to unit 1460-4FAIL (nothing sent)
L12Misspelled tenantSaid it could not find themPASS
L13Conflict on unit 1460-4Asked about itPASS
L14"Approve, send the rest"Approved the list; no tenant message went outFAIL
#DefectFix PR (all six merged on main 2026-10-16, no switch, live everywhere)
1An approved list sends nothing: its held messages had already expired, yet Clara replied "everything else goes out as listed".#20370: Clara now says what actually goes out and names each row that has nothing to send
2The reviewer's $300 concession on unit 101 was lost: the row had no offer yet, and the scan built a fresh one from policy. ("Send the rest" starting a row held only for a balance is by Fede's 2026-10-14 ruling, not a defect.)#20366: the scan applies the approved decision to the offer it saves
3A correction ("Actually…") is read as a tenant name.#20377
4A unit not on the list is matched to the nearest one.#20369 (merged)
5The "which lease?" question offers a struck row.#20390
6Any reply Clara did not act on is stored as an open question with no lease.#20396

7.2 · Practice round on Camellia's real renewal meetings

We read the raw transcripts of six Camellia team meetings that walked renewals (Jul 16 to Oct 15), wrote down what the team decided for each unit, then ran today's engine on each meeting against the list Clara would have had that day. Read-only: 0 writes, 0 sends. 3 runs each; a separate Opus judge graded every row, and both planted wrong rows went red. The answer key was locked before the first engine run. The Oct 14 meeting is Western Slope's (7.3); Camellia's that week is Oct 15.

Jul 16 · 10match: 5ambiguous in the meeting: 5Aug 6 · 18match: 7miss: 1asked back: 3ambiguous in the meeting: 7Aug 13 · 18match: 11asked back: 1ambiguous in the meeting: 6Aug 20 · 16match: 6asked back: 2ambiguous in the meeting: 8Sep 17 · 6match: 3asked back: 1ambiguous in the meeting: 2Oct 15 · 21match: 7asked back: 1ambiguous in the meeting: 13
Rows per meeting, run 1 of 3. matchmissasked backambiguous in the meeting
MeetingUnitsMatchPartialMissAsked backAmbiguous
Jul 161050005
Aug 61870137
Aug 1318110016
Aug 201660028
Sep 17630012
Oct 1521700113
All893901841

Runs 2 and 3 within one row per column. The one miss (Camellia 415) is a gap in our list rebuild, not the engine.

The engine never overreached: 0 wrong actions, 0 made-up quotes. But it acted on only 1 of the 39 matches; the rest were correctly staying quiet. The real gap is the 41 rows where the team's words don't map to any decision Clara has.

Why rows were lostHow oftenExampleKind
Transcriber splits unit numbers ("3 11", "6-14"), the right row is rejected3 rows, all asked backCamellia 311bug
Unit named on one line, decision on the next5 rows, all asked backCamellia 515: "515?" then "she left without saying anything"bug
A quote that spans two lines is dropped1 rowCamellia 204: sent to the lawyers, don't offerbug
Same meeting, different answer per run2 of 6 meetingsCamellia 518 vacating in 1 of 3 runsbug
"They're gonna renew": no decision exists12 rows, engine does nothingCamellia 402policy
Paper lease: no decision exists10 rows, asked, held or nothingCamellia 106policy + design
Unit not on the list that day12 rows, reported correctlyCamellia 415data

Decisions for Fede

  1. What "they're gonna renew" means: (a) mark intent and skip the chase, (b) still send the offer, skip only the follow-ups, or (c) no decision, as today. Recommend (b): note "team expects renewal", keep the offer going, stop the reminders, never mark renewed until AppFolio shows it signed.
  2. Paper lease (proposal, not built): a "paper lease" decision stops outreach and re-engagement for the cycle and shows "PM still has to print and upload". Where the marker lives: (a) the list row and the unit's renewal page, (b) also a "waiting on upload" group in the weekly pre-read, or (c) a staff email. When it clears: (i) when the PMS shows the signed lease, (ii) when staff marks it, or (iii) at lease end. Recommend (a) + (i), no button; if lease end passes unsigned, the row goes back to the team as a question, never to the tenant.

The four bugs are fixes with no switch, next in the reader lane. Files: transcripts, answer key, engine runs and judge grades in the lane scratchpad (ws-arch/camellia-replay).

7.3 · Practice round on Western Slope's Monday board, simulated reviews

We turned the team's board notes into the replies Bev or Kat would have sent to Clara's monthly list, and ran them through today's reader and engine against Western Slope's real book. Read-only: 0 writes, 0 sends. 3 runs each; a separate Opus judge graded every row, and both planted wrong rows went red.

Before: proven on 14 test replies. After: 36 real board rows. Written the way Bev writes, Clara recorded the decision on 2 of 36; with the resident's first name added, 12 of 36.

How far back: November 2026. The board goes back to April, but Clara's copy of Western Slope starts Sep 13 and keeps only current leases, so only November, December and January can be replayed (23 of 199 board rows).

Nov · as writtenmatch: 1miss: 2asked back, nothing recorded: 4ambiguous on the board: 4Nov · with namesmatch: 1miss: 0.33asked back, nothing recorded: 5.67ambiguous on the board: 4Dec · as writtenmatch: 1asked back, nothing recorded: 8ambiguous on the board: 4Dec · with namesmatch: 1asked back, nothing recorded: 8ambiguous on the board: 4Jan · as writtenasked back, nothing recorded: 11ambiguous on the board: 1Jan · with namesmatch: 10asked back, nothing recorded: 1ambiguous on the board: 1
Rows per lease-end month, average of 3 runs. Top bar: written the way Bev writes. Bottom bar: resident first name added. matchmissasked back, nothing recordedambiguous on the board
Lease-end month (list sent)RowsMatchPartialMissAsked backAmbiguous
November 2026 (Aug 11)111 / 10 / 02 / 0.34 / 5.74 / 4
December 2026 (Sep 1)131 / 10 / 00 / 08 / 84 / 4
January 2027 (Oct 13)120 / 100 / 00 / 011 / 11 / 1
All362 / 120 / 02 / 0.323 / 14.79 / 9

As written / with names, average per run. Ambiguous: the board does not say one thing.

The engine decides well: with names, 74 of 81 clear rows right. The reader loses them: one unclear row freezes the whole reply, so 24 of 36 replies recorded nothing.

Why rows were lostHow oftenExampleKind
A house named by its street address cannot be pointed at6 of 18 replies froze as written; 0 with names"Nashua house - same rent" → "I could not tell what you wanted"bug
A number inside a street name read as a unit ("1/2", "1/8")9 of 36 replies frozea Morningside house with a ½ in its number, confused with Hill Avenue 2bug
A teammate's name read as a resident3 of 3 December runs with names"Kat to reach out to the housing authority" → "I could not find Kat on this month's list"bug
One unclear row freezes the whole reply24 of 36 replies recorded nothingJanuary: engine decided 7 of 10 rows, nothing recordedpolicy
"The resident says he is renewing" sends the offer again2 rows: sent 6 of 6 as written, 1 of 6 with namesColorado Avenue Bpolicy
"Accepts the promo", promo not on the list1 row, asked 6 of 6Morningside house: Clara asks what the promo was (right)data
A "?" in a reviewer line refuses the whole reply2 board notes; not in these replies"can she get a new cosigner?"policy

Do not contact / do not renew: 7 rows, a status mark only, none on a replayed list, so the engine never reached them. Clara has no copy of that mark; she learns it only when the reviewer says it on the list. "Wants renewal", nothing sent: 11 rows, all before November. Concessions: kept in the team's words when reached. No Clara decision yet: housing-authority holds (Clara held or asked), roommate swaps (Clara asked who, right), paper letters, cosigners.

Decisions for Fede

  1. One unclear row in a reply: (a) record the clear rows and ask only about the unclear one, or (b) keep today's all-or-nothing. Recommend (a).
  2. The reviewer says the resident already agreed to renew: (a) mark it handled by the team, no new offer, (b) send the listed offer, or (c) ask each time. Recommend (a): Western Slope sends that lease themselves.
  3. A "?" in a reviewer line: (a) answer it and still record the other lines, or (b) refuse the whole reply as today. Recommend (a).

The three bugs are fixes with no switch, next in the reader lane. Files: answer key, replies, engine runs and judge grades in the lane scratchpad (ws-arch/monday-replay).

8 · Open questions

#QuestionWho answersRow
1Does Camellia's AppFolio already send its own offer emails and reminders next to Clara's texts, two cadences today?Engineering: one Camellia tenant's Emails panelC2 C40
2Clara's first touch at Western Slope: a text, as the engine does today, or an email like Bev's?Their team, at Tuesday's meetingC1 C36
3Between a tenant's yes and the AppFolio offer: who builds it, how long it takes, and when the lease templates are readyKat and JayC41 C40
4Where did the two move-outs on their board give notice, when PropFlow has no record and the tenant sync last ran Sep 9?Engineering first, then their teamC49 C18
5Where do the prices come from: the unit pricing matrix from their budget, which Kat works from?KatC41
6Does an invite to hello@ reach Clara, or should Jason use the shared Clara address?EngineeringC47 C41

9 · Engineering notes (appendix)

For engineers. File names, line numbers and PR numbers appear only in this section.

9.1 Where each slice plugs in

SliceSeamCodeNotes
1 · staff-touch checkThe per-send review step every renewal message already passes, ahead of the Supervised checkrenewal activities 947–952, 1477–1482, 1910–1915, 2246; text review 88–94; email review 68–76; read-person-picture.tsThe step is an activity, so running renewals replay unchanged. A held message reuses the park or reject kinds per D2, never the 24-hour expiry, which pages the manager C35 C46 C52
2 · confirmationThe reply reader: a reply produces the confirmation instead of the approval; approving the confirmation applies the edits and approves the listbatch-reply.ts:1–33, 414; the list's renderer; the coworker email doorThe confirmation records what it listed; a lease changed after it is held, not sent. Releasing parked first messages is unchanged and not yet verified in production C37 C13 C32
3 · list on its own settingThe list gate in the daily scan, plus the per-send step's list check when a company is Live with the setting onscan-batch.ts:85–89, 136–140; review-offers-before-sending.ts:12–21; keys.ts:1391–1398A data step first writes "off" for every company on Live today, so their behavior is unchanged C34 C40
4 · weeklyThe scan's month key becomes a company-week key; the time comes from the new company settingscan-batch.ts:2, 7–11, 123–125If the workflow's park path changes, it carries a patch marker and climbs rung 4 (workflow histories; renumbered 10-17) C33 C52
5 · note readerEmail notes intake and meeting notes into the company brain; one staff-only readerstaff-meeting-notes.ts:12–16; meeting-notes.ts:34–36; the private-notes lint allowlist (2 files)The reader's output reaches only the confirmation, a staff email; the replay cases and controls live in the prototype folder C17 C47 C19
6 · what was sentThe sync's renewal writer, the mirror's rows, the robot's inbox list readpms/writers/renewal.ts:532–551; file-message.ts:8, 167; robot lib/textingInbox.ts:166 (appfolio-browser-agent PR #530)Today the writer drops the offer and logs "manual cancel needed". The picture leaves out bulk sends and history rows (read-person-picture.ts:24–33; message-provenance.ts:309–315): add them as "what was sent" items, never as teammate touches C57 C46 C44 C56
RuleSlices 1, 2, 3 and 6 change no workflow code: only activities, the scan, the reply reader and the sync. Any workflow change carries a patch marker, as renewal_held_text_expiry_v1, renewal_batch_park_v1 and renewal_reject_stops_reminders_v1 did, and climbs rung 4 (workflow histories; renumbered 10-17) C52
BudgetEvery check reads what the sync and the mirror already stored; nothing calls AppFolio at send time, and a per-renewal AppFolio read is ruled out. Only the sync talks to AppFolio, once per client; the mirror's ceiling is 4,000 requests a day, at about 10 per thread, an estimate C51
PagesNo slice adds a per-tenant page or email to staff. In Supervised, held messages show on the pre-read and the list only

9.2 Conflicts and peer lines

WithWhatHow this page handles it
Gera's portfolio model: the org is the wallWhere notes and invites go. The brain page says the shared Clara address, with the company taken from the sender's domain, and also a per-company Clara mailbox; the code matches by sender domain; Gera's model keeps per-org addresses wanted; on 10/14 Gera pointed their invite at hello@ C47 C41Today: the shared Clara address, matched by domain, as built. The per-company address when Gera's per-org addresses land. Hello@ is open question 6. Everything this page adds is company-level, the org in Gera's model: the schedule, the reviewers, the door
AppFolio Communications laneThe inbox mirror is leasing only; tenant threads are out until Fede rules; Clara never wakes on a mirrored row; the queue for failed AppFolio writes (their 8d) is pending C44Assumes none of it. Slice 6's texts and the AppFolio door for tenants wait on that lane; until then the team's review of the pre-read is the guard
Lead Intelligence laneThe weekly review is one more alarm into the same loop, with the pre-read and the meeting notes as picture inputs; the four rules; a teammate's touch is derived, never a setting C50Reuses the picture, the alarm seam and the four rules. Built in that lane today: the person picture (thread, card creator and status; notes, activity and assignee not yet fresh at every wake), a stop/wait/send follow-up check in three prospect senders (rules only, fails open after 8 s), and the alarm seam with one caller, the after-tour check-in. Not built: the alarm reading the picture, the judgment step, the per-company lead-source list (armed, dark on merge) C46; moving renewal timers onto it is a later migration with its own patch marker
The 10/12 autonomy pageD1 (b): an approved list sends at once C40Superseded 2026-10-15 by the confirmation, for both inputs C42
Fede, 10/09: one list on the 1st, no setting for itThe monthly rhythm C40Superseded by the 10/15 weekly cycle on each company's day and time C43; the day and time is a new company setting, dark (slice 4)

9.3 Tuesday mechanics

ItemWhat happensRow
The flipRenewals off to Supervised opens the first list that minute; the next list comes a month later, until slice 4C40 C33 C34
ReviewersThe list goes to the company's renewal reviewers; the 10/12 plan named Kat and Jay, and with none it goes to nobody. Their stored reviewers are not yet verifiedC40
Mid-month leasesA lease that opens after the list went out gets a 24-hour hold, which expires, stops the reminders and pages the manager, until slice 4C40 C52
PaperworkUnset means their team: the workflow seeds "prepared" and skips the letter, which otherwise goes as a picture message from our own line; "prepared" is not on the reminder stop list, so reminders run until an answerC55 C39 C36
TextsFrom Clara's own line, as the 10/12 plan had them; the AppFolio text switch would hold every renewal text until tenant threads are mirroredC38 C40 C44
JanuaryAll 10 got Bev's price email on Oct 13. The start check counts only an AppFolio offer, never a staff email, so Clara would offer again: the team strikes them in the replyC49 C45 C37
NotesForwarded notes are matched to the company by the sender's domain and stored; nothing reads them until slice 5C15 C47 C17
The inviteThe video join is off. As built it skips recurring invites, and their meeting is weekly; it joins 1 minute early, gives up 30 minutes late, ends a call at 15 minutes and labels every speaker "Participant"C15 C28
Month-to-monthFede's ruling: off at Western Slope. In Supervised every automatic message is held for us, so a month-to-month warning would wait; which setting keeps it off in Live is not yet verifiedC43 C40
ApprovalUntil slice 2, approving the list sends the offers at once, within secondsC53 C40

9.4 Claims register

Every C# on this page points here. VERIFIED means someone looked at the ground truth itself and the artifact is named; PARTIAL rows say what is not yet verified. Inferred claims are kept off the page.

#ClaimStatusProof
C1Bev's renewal price email goes out through AppFolio from the shared Assistant PM login, with Opened and Delivered statusVERIFIEDFede's screenshot of one tenant's Emails panel; the emails export (Aug 11 "Upcoming Lease Renewal", from the Assistant PM login)
C2AppFolio emails the tenant "Review your renewal offer" when the office creates a Renewals-module offer, then reminders on day 1, 2 and 7VERIFIEDEmails export: Oct 6 offer; reminders Oct 7, 8, 13, from AppFolio's no-reply address
C3Tenant email replies come back into AppFolio, both waysVERIFIEDEmails export: a "Re: Renewal" thread, Nov 2025, from the tenant and through AppFolio's mailer for the company
C4AppFolio's Inbox shows emails and texts in one thread timelineVERIFIEDFede's screenshot, 08:42 MT
C5The thread history our robot fetches is texts only; email cards are not in itVERIFIEDAppFolio Communications session, 2026-10-15: 1,871 messages and 433 list rows, 0 email items; no channel field; list rows type "sms"; the /sms endpoint has no channel filter; 0 hits for AppFolio's email senders or subjects
C6Their renewal offers reach tenants as AppFolio bulk texts on Sep 28 and Oct 6; 2 of 8 December units have oneVERIFIED (texts)Raw capture and live read, 2026-10-15 (pms-mirror-harness out/ws-renewals-2026-10-15)
C7The inbox mirror is on only at Willows, off at Western Slope and Situs; leasing only; tenant threads heldVERIFIED by the owner lane · updated 2026-10-19: the mirror is now ON at Western Slope (910 rows since the Sep 30 look-back), text door unset; see C65AppFolio Communications session, 2026-10-15
C8Western Slope's renewals module is off; prospects and maintenance onlyVERIFIEDProduction read 2026-10-15, enabled modules
C932 Western Slope leases end November 2026 to February 2027VERIFIEDProduction read 2026-10-15
C10AppFolio's renewal summary report carries the sent date; the sync opens the renewal as "offer prepared", and the board shows "waiting" with an "Offer sent" dotVERIFIED (corrected)File 19, row 10: adapter, writer and board lines; production 14:47Z: 2 November rows with an Oct 6 AppFolio offer, opened by the sync Oct 6 22:21Z, bucket waiting. 3 waiting rows, not 4; the words "waiting on tenant" appear only on month-to-month rows
C11No API report or robot route reads a tenant's Emails panel or CommunicationsVERIFIED (PropFlow side)File 19, row 11: all 54 robot routes and 17 report names, 0 tenant email reads. Caveats: the guest-card read has an email channel (prospects); AppFolio notification emails are parsed from a connected mailbox; robot server code not inspected
C12Their Monday board: 17 of 32 rows disagree with PropFlow; January emailed Oct 13; December emailed Sep 1VERIFIEDMonday export parsed (ws-arch-scripts/parsed.json); 13-monday-board-analysis.md
C13One renewal workflow per lease; approval releases parked first messages; no weekly or per-company schedule; "check before send" never builtPARTIAL: release by approval not yet verifiedFile 19, row 13: queue, per-lease id, waits, gate and schedules quoted; Fairhaven: 3 list approvals sent offer texts SMc168c9…, SM3995707…, SM282ef1… (holds made and approved in under 1 s, not parked). No hold has been parked and then released by approval
C14Renewals have no "a teammate already reached out" check; only a human-replied flag on the text and letter, set by a manager's email replyPARTIAL: code verified, planted case not runFile 19, row 14: one writer (record-pm-reply.ts:182, PMS delivery only), readers quoted; the renewal email path never reads it; the mirror never holds. The planted Fairhaven case is written, not run
C15The video join is off at Western Slope and notes by email are on; recurring invites are skipped; a call ends at 15 minutes; every speaker is "Participant"VERIFIED (one part corrected)File 19, row 15: production 14:53Z, join unset so off, notes intake on and matched by sender domain; meeting-invite.ts:16, 192–198; call-binding.ts:47–51 (max_call_duration 900); meeting-notes.ts:34–36
C16No invite from Western Slope has reached Clara; no Monday guest inviteVERIFIEDProduction read of 501 inbound email records since Oct 13
C17The company brain store exists; Clara never reads notes when answeringVERIFIEDFile 19, row 17: the lint allowlist has 2 files, both only save notes; no app-code reader
C18Tenant sync: 0 runs since Sep 9VERIFIEDProduction run log (issue #20009)
C19Prototype: meeting transcript to per-lease decisions, every row right, 3 runs on each of 7 cases, 0 invented quotes, controls redVERIFIEDpoc-notes-to-decisions/runs and grade.py, re-runnable
C20Their leasing mailbox: 1,832 messages ingested, 0 renewal offer emailsVERIFIEDProduction read 2026-10-15 (ws-renewal-state/ingest.json)
C22Jay's "has opened e-mail" tracking is AppFolio's email trackingVERIFIED by C1 and C2Emails panel screenshot (Opened status)
C23Nothing in PropFlow reads or sends the email side of the AppFolio inboxVERIFIED by the AppFolio Communications session; all-channels read approved 2026-10-15, result pendingScoped search of the app, robot, mirror harness, docs, issues and PRs, 2026-10-15. Not to double-count: AppFolio notification emails parsed from the client's own mailbox; the robot's read of the renewal letter PDF; the email-only application send (#13626 merged, #14064 open)
C24The inbox list read is hard-coded to texts and its route takes no channel switches; separately, the guest-card route already asks AppFolio for email (prospects only)VERIFIED in code; no email row captured yet. Approved 2026-10-15 (Fede: "yes, of course. Should include all communications."); owner: AppFolio Communications session; open as appfolio-browser-agent PR #530: the list read takes texts, email and chat switches, default unchanged, the probe opts into all, the default flips after the probe; per-number history stays texts only. Result pendingRobot lib/textingInbox.ts:166; robot lib/apiClient.ts:3937–3943. The guest-card route can trigger a login on a cold session, so it was not run unattended
C25The board's "Offer sent" dot is filled from the renewal's open time when no letter time existsVERIFIEDmap-renewal.ts:763–764; board-shared.ts:234
C26Under an approved list, a day-0 offer text gets a per-send hold made and approved in under 1 secondVERIFIEDFile 19, row 13 (c), 3 Fairhaven holds
C27No production property has its delivery mode set to AppFolio (0 of 159), so the human-replied flag is written nowhere todayVERIFIEDFile 19, row 14 (c); verify/r14.out.json
C28Meeting join: 30-minute late limit, joins 1 minute early, 900-second call capVERIFIEDmeeting-invite-intake.ts:49, 170; meeting-invite-workflow.ts:38, 40, 106; call-binding.ts:47–51
C29The renewal email path never reads the human-replied flagVERIFIEDFile 19, row 14 (a)
C30Reminder waits default to 24 hours and 7 days; comments saying 48 hours and 5 days are staleVERIFIEDFile 19, row 13 (a)
C31The robot's guest-card messages read carries an email channel, for prospects onlyVERIFIEDFile 19, row 11
C32All 6 Fairhaven holds ever parked on a renewal list were rejected; none was released by approvalVERIFIEDFile 19, row 13 (c); verify/r13.out.json
C33The list opens once a month in the daily scan; there is no weekly or per-company scheduleVERIFIEDscan-batch.ts:2, 7–11, 123–125; schedules in file 19, row 13
C34The list opens only when the building is Supervised and "Review offers before sending" is on; unset means on; a header comment is staleVERIFIEDscan-batch.ts:85–89, 136–140; review-offers-before-sending.ts:12–19, 21; keys.ts:1391–1398
C35Every renewal message passes one per-send review step; it checks Supervised first, and in Live it sends with no check; there is no check-before-send stageVERIFIEDRenewal workflow 3736, 3847, 3874, 3963, 3992, 4106; activities 947–952, 1477–1482, 1910–1915, 2246; text review 88–89, 94; email review 68–73, 76
C36One workflow per lease; the offer goes by text, by email only to a tenant with no phone; reminders on day 2 and day 9; they stop on an answer, a signature, a notice or a manager decision; "prepared" is not a stopVERIFIEDclient.ts:158; renewal-email-review.ts:4–5; renewal workflow 3900, 3922–3926, 3928–3937, 3103–3108
C37The reply reader for the list exists: approve, change or skip by email replyVERIFIEDbatch-reply.ts:1–33, 414
C38The AppFolio text door is one company switch, off by default, with no fallback; it needs the tenant's mirrored thread, or the text is held; its first live send was at Willows on Oct 13VERIFIEDdispatcher.ts:494–499; text-door-address.ts:1–6, 57; AppFolio Communications session (Oct 13 send)
C39The renewal letter goes by picture message from our own lineVERIFIEDsend-renewal-letter-mms.ts:16–23, 331
C40The 10/12 autonomy page and its ruling log: levels as presets of settings, Camellia at level 3; D1 (b) chosen 10/12, "check before send" was option (a); the flip opens the list that minute; reviewers Kat and Jay; the templates are Jay's; Live from about 10/21; leases opening after the list get only 24-hour holds; the list review its own setting, 10/13; Supervised holds every automatic message; Fede 10/09, one list on the 1stVERIFIEDrenewals-levels-of-autonomy-2026-10 extract, lines 54, 56, 58, 72, 101, 108, 155, 157, 173, 201, 245, 353, 355, 506, 632, 1580, 1588
C41The 10/14 weekly sync with their team, quoted from the raw per-speaker transcript; lines labeled "J." are attributed to their teamVERIFIED#transcripts thread, lines 310, 1069, 1073, 1099, 1132, 1144, 1146, 1200, 1237, 1264, 1277, 1291, 1298
C42Fede's raw notes of 10/15: the weekly loop, notes to the company brain, the confirmation, both inputs, tenant history and market as inputs, the 80/20 end state with no meeting and no approvalVERIFIEDFile 15, lines 33–45, 48–60, 62–88
C43Fede's Western Slope rulings of 10/15: weekly on each company's day and time, Tuesday pre-read, 11:30 meeting, Thursday sends; month-to-month and the contract off; both modes; one per-company AppFolio setting as the end state; the notes MVP for 10/20VERIFIED (dictation record, matched by transcript lines 1073, 1237, 1277)File 00, items 3, 4, 4d, 5, 10
C44AppFolio Communications lane: the mirror is leasing only; tenant threads are out until Fede rules; Clara never wakes on a mirrored row; their 8c is proposed and 8d is pendingVERIFIED by the owner laneFile 07 notes; their page's 8c and 8d headings; file-message.ts:8, 167
C45The start check skips a lease only when an offer is already prepared or open in AppFolioVERIFIEDrenewal-classify.ts:145–148, 277–283
C46The person picture leaves out bulk sends, notices and history rows; a follow-up gate over it fails open; the alarm seam has one caller, the tour check-inVERIFIEDread-person-picture.ts:24–33, 145–154, 279; message-provenance.ts:309–315; follow-up-gate.ts:7–13; scheduled-wake.ts:31; tour-checkin-wake.ts:53–54
C47Where notes go: the brain page names the shared Clara address matched by sender domain, and also a per-company mailbox; the code matches by sender domain; Gera's model keeps per-org addresses wanted; Gera named hello@ on 10/14VERIFIEDcompany-brain-design extract lines 78, 133, 393; staff-meeting-notes.ts:12–16; portfolio-architecture extract line 4960; transcript line 1146
C48One November lease in AppFolio: Aug 11 price email, Aug 18 nudge text, a yes on Sep 28 and 29, the offer Oct 6, reminders Oct 7, 8 and 13; the tenant page holds the whole historyVERIFIEDEmails and texts exports, dates only; files 16 and 17
C49January: all 10 rows carry Bev's Oct 13 email note on their board; PropFlow shows 8 not started, 1 needs you, 1 settled leaving, and no offer record; two move-outs on their board have no PropFlow recordVERIFIEDws-arch-scripts/parsed.json; ws-renewal-state/board-rows.json (08:08)
C50Lead Intelligence lane's design, not built: the four rules, the weekly review as one more alarm, re-alarm three times, a teammate's touch never a settingVERIFIED as that lane's statementFile 09 notes; the lead-source-gate page
C51Only the sync talks to AppFolio, once per client; the mirror's ceiling is 4,000 requests a day, about 10 per threadVERIFIED (per-thread figure is an estimate)prospect-conversion.test.ts:278; watch.ts:107; file 12
C52A held message expires after 24 hours: the reminders stop and the manager is paged. A message parked on an unapproved list never expires. A reject stops the reminders with no page, and the board shows "needs you"VERIFIEDRenewal workflow 2441–2470, 2477–2482, 4159–4185; held-message-max-age.ts:17
C53Three Fairhaven list approvals sent the offer text 18 to 26 seconds later, two on the page and one by email replyVERIFIEDFile 19, row 13 (c); SMc168c9…, SM3995707…, SM282ef1…
C54The prototype re-run on 2026-10-15 and the added G6 controlVERIFIEDgrade.py; poc-g6/make_g6.py and its case file
C55Who sends the paperwork: unset means their team; with their team there is no letterVERIFIEDkeys.ts:1374–1385; renewal workflow 3727–3729
C56The conversation in one place: the inbox list read for email rows, per-number history for texts, the guest-card read for prospects. History stays texts only because AppFolio keys email history by guest card. The email row shape is not yet seenVERIFIED by the AppFolio Communications sessionDecision log 2026-10-15 16:00Z; appfolio-browser-agent PR #530
C57While Clara's renewal is open, the sync drops a new AppFolio offer and logs "manual cancel needed"VERIFIEDpms/writers/renewal.ts:532–551
C58Inbox list probe (deployed robot at appfolio-browser-agent #530, Western Slope, 2026-10-15, 5 requests, 0 logins, nothing written): default 20 text rows; texts+email byte-identical to default (55,074 bytes); email only → 0 rows; texts+chat → 19 texts + 1 chat. Email is not served by the list endpoint; per-person history serves texts and emails mixed, read today for prospects onlyVERIFIED (AppFolio Communications session)~/agents/pms-mirror-harness/out/inbox-email-probe-2026-10-15/
C59Per-person communication history route (appfolio-browser-agent #532, merged 2026-10-15): one Western Slope tenant, all channels, limit 20 → HTTP 200 in 3.0 s, 14 texts (8 out, 6 in) + 6 outbound emails, no chat; rows typed by channel; per-channel cursor {sms, email}; email filter honored. Unverified: applicant/occupancy parties; max_id cursor boundaryVERIFIED (AppFolio Communications session, production, read-only)harness out dir (raw capture with PII, not copied)
C60Fede's 2026-10-19 ask: renewals at Western Slope this week, offers through AppFolio, each outreach held for his review, replies in Supervised, "100% certainty that nothing will leak"VERIFIEDSession 002 transcript, 2026-10-19 afternoon (dictated)
C61Western Slope today: 30 AppFolio e-sign renewal offers sent Jun–Oct (25 signed, 5 open); 7 renewal texts from Bev to 6 tenants Sep 30–Oct 19 (6 bulk on Oct 6, 1 personal Oct 16, a "yes" reply nobody followed up in our copy); 0 renewal emails sent from leasing@ among 375 sent rows; AppFolio's own offer email is not visible to usVERIFIED (production, read-only, 2026-10-19)door/renewals/ws-renewals-today.md §A, §F; raw: work/ws_dynamo.json, work/ws_email_ingest.json
C6234 leases (59 people) end Oct 19–Feb 28: Oct 2, Nov 6, Dec 8, Jan 10, Feb 8; 4 carry an AppFolio offer; Renewals module Off; policy stored (90 days, 12 months flat, +$150 month-to-month, paperwork by the team); PropFlow has sent 0 renewal messages at Western Slope; lease data mostly from Sep 13VERIFIED (production, read-only, 2026-10-19)ws-renewals-today.md §B, §C; work/live_leases.json
C63The AppFolio text door replies on an existing thread for party types tenant, applicant and prospect, but starts a thread only from a guest card (robot route /api/guest-card/message); a tenant with no mirrored thread is held no_pms_record, re-driven about 10 minutes, then held with one engineering alert, never sent from Clara's line. Of the 59 people, 12 have a thread in the mirror copy (Oct 0 of 2, Nov 1 of 12, Dec 4 of 14, Jan 4 of 12, Feb 3 of 19); all 59 have a phoneVERIFIED (code at origin/main 45fded2f77; robot 5dc1d02; production mirror copy 2026-10-19 14:21Z)door/renewals/code-gaps.md §8; text-door-address.ts:60–79; appfolio-text-start.ts:1–30, 86–105; appfolio-inbox-text.ts:296–300; ws-renewals-today.md §G
C64Supervised holds every renewal text, reminder, letter and email, but an approved list releases each parked offer and every later reminder under the approver's name, Supervised or not; Western Slope's renewal reviewers are jay@ and kat@ (set Oct 12), fede@ is not oneVERIFIED (code + production, 2026-10-19)renewal-text-review.ts:110, 126; renewal-email-review.ts; settle-batch.ts; scan-batch.ts:22 (stale comment); ws-renewals-today.md §G
C65Tenant threads are held tenants_later (not filed, no wake); Clara's own door text is the one exception; the wake rule needs Clara's text newest office-side; the woken envelope is labelled prospect; Oct 19 door proofs (reply loop, double text, STOP/START, stays-on-Clara's-line) were on a prospect thread, never a tenant; the inbox mirror is on at Western Slope (910 rows, 853 texts, 57 emails, 22 held, newest 19:21Z) and the text door unsetVERIFIED (code + production, 2026-10-19)file-message.ts:233–256; wake-on-reply.ts; pms-mirror-reply-wake.ts:41; appfolio-text-door memory note; ws-renewals-today.md §G
C66The decision engine is source-agnostic (reply, notes, transcript) with quotes checked in code, but its only live caller is the list-email reply reader; meeting join and notes-by-email feed the company brain, not the list; the dispatcher's input already carries kind (e.g. renewal_outreach_sms) and a required module, and resolveCompanyTextDoor receives only the company, so a renewals-only door scope is a read in the resolverVERIFIED (code at origin/main 2f1a154662)renewal-decisions/engine.ts:1–80; staff-reply/batch-reply.ts:42; dispatcher.ts:222, 245, 523; company-text-door.ts
C67POC replay over the Western Slope (PMSMIRROR westernslopepm, 707 held tenant rows / 245 threads) and Willows mirror copies: 0 wakes under today's rule and under the renewal guard; 193 mixed threads; 37 two-tenant threads; 6 person-phone mismatches; no label judge exists; the echo of a door send is stamped clara_reply and the outbox record keeps no kindVERIFIED (local harness, production reads only, 2026-10-19)door/renewals/poc-tenant-threads.md; harness under door/renewals/poc/ (raw data not scrubbed, stays local)
C68AppFolio texts a tenant from the tenant page with no prior thread (Text button; Text Unit; "Reply STOP" on the first text to a new number; texts are tied to phone numbers, not people). Our robot's inbox send (origin/main 9cd3cda, last touched 2026-10-15) requires lastSeenMessageId, refuses a phone with no thread (thread_not_found) and refuses the tenant party outright (OBSERVED_SEND_SHAPES.tenant = false → unproven_send_shape); the only proven shape is the prospect guest-card capture of 2026-09-02; it POSTs /sms/send_text_message with a CSRF token from the record page, so a tenant-page send is the same endpoint from a different pageVERIFIED (AppFolio help articles "Texting from AppFolio", "Bulk Texting Tenants", "Universal Inbox"; robot lib/textingThreadSend.ts:40, 53–57, 195–224, 254, 288, 316, 335; route.ts:28–46)pms-knowledge-base/appfolio/help-articles; robot repo origin/main

10 · Update 2026-10-19: renewal offers through AppFolio, every message approved by Fede

Fede, 2026-10-19: "the priority this week is to turn on renewals for Western Slope… send renewal offers through AppFolio, so they know that it's the team… hold each outreach for review… if someone responds, supervised mode… 100% certainty that nothing will leak by accident without me approving every message." This section is the gap map he asked for: what exists, what is missing, the smallest build, four calls. The Oct 20 dry run in section 6 stands unchanged; nothing here goes to a tenant before it.C60

30 + 7 + 0
how Western Slope tells tenants today: 30 AppFolio e-sign offers Jun–Oct (25 signed), 7 texts from Bev in the 19 days we hold, 0 renewal emails from their leasing inbox C61 C1
34 leases
end Oct 19 to Feb 28 (59 people); 4 have an AppFolio offer; Clara has sent 0 renewal messages here; Renewals is Off C62
0 of 59
tenants the AppFolio door can text today: the robot refuses every tenant send until the tenant send shape is captured once at the Willows (corrected 16:40 MT; 12 of 59 have a thread to reply on after that) C68 C63
0 of 2
renewal reviewers at Western Slope are Fede (Jay and Kat), and their list approval releases every offer at once, Supervised or not C64

How they do it today, and what "through AppFolio" can mean

Fede guessed "just text". It is both, all inside AppFolio and nothing from their leasing inbox: Bev's price email from the shared Assistant PM login (August, C1), a bulk text about three months out and a personal nudge text later (October), then the office creates AppFolio's renewal offer, AppFolio emails it with its own reminders, and the tenant e-signs.C61 C48 Tenant replies, by text or email, land in AppFolio.C3

LegCan Clara send it as the team today?Call
Text in the tenant's AppFolio threadNot yet, for any tenant. AppFolio itself texts tenants from the tenant page with no prior thread (Text button, Text Unit). Our robot's inbox send refuses the tenant party as an unproven shape, and refuses a phone with no thread; the app side starts threads only from a guest card. Fix: capture one real tenant-page text at the Willows, allow the tenant party, and let a tenant send use the tenant page as its form source (a day, robot repo), then 12 of 59 are reachable at once and the rest need the thread start C68 C63The channel for this launch
Email from AppFolioNo. Nothing in PropFlow or the robot sends AppFolio email; the inbox list endpoint does not even serve it C23 C58Deferred; not a this-week build
Email from leasing@westernslopepm.comYes (connected, we see its sent mail), but no renewal has ever left it, so it would not look like the team C61 C20Off; keep as today (no-phone tenants only)
The AppFolio offer and e-signStays with the office (Fede, 2026-10-15) C43 C55Decided, unchanged

Fede's flow against the code, step by step

flowchart TB
  subgraph S["Sending the offer"]
    direction LR
    A["Team meeting\nnotes"] -->|"no path yet"| B["Decision\nengine"]
    B -->|"built: replies to the\nlist email only"| C["Month's list\napproved by Jay or Kat"]
    C -->|"HOLE: approval releases\nevery offer at once"| D["Fede approves\neach offer"]
    D -->|"HOLE: company-wide door,\nno tenant thread start"| E["Text lands in the\ntenant's AppFolio thread"]
  end
  subgraph R["The tenant answers"]
    direction LR
    F["Tenant\nreplies"] -->|"HOLE: tenant threads\nnot filed, no wake"| G["Clara's reply\nheld for Fede"]
    G -->|"built: Supervised,\nthree carve-outs"| H["Fede approves,\nsent in AppFolio"]
  end
  E --> F
  classDef hole fill:#fde8e8,stroke:#c0392b,color:#7a1c1c;
  classDef ok fill:#e8f5e9,stroke:#2e7d32,color:#1b4d1e;
  class C,D,E,F hole;
  class B,G,H ok;
Green: built and proven at Fairhaven or the Willows. Red: a hole for "nothing without Fede". Proof so far was on a prospect thread; no tenant has been texted through the door yet.C64 C65
PieceBuiltHoleFix size
Meeting notes → decisionsEngine takes any text (reply, notes, transcript) and records per-lease decisions with the quote; meeting join and notes-by-email land in the company brain C66Nothing routes the notes to the list; today a human pastes them as a reply to the list emailhours; optional for week 1
Hold each offer for FedeSupervised holds every renewal text, reminder, letter and email on the approval queueApproving the list releases every parked offer and every later reminder at once, even at a Supervised building (renewal-text-review.ts:110,126, settle-batch.ts). The only human step is the list approval, which Western Slope's reviewers do (Jay and Kat; Fede is not a reviewer) C64hours
Send through AppFolioThe offer text and reminders already go through the dispatcher, so the door applies; the app addresses a tenant party on an existing thread, but the robot refuses tenant sends until the shape is proven C63 C68The inbox mirror is already on at Western Slope (910 rows since Sep 30), the text door is unset. One company switch moves every Clara text (leasing too), and it is the switch Fede put on hold this morning pending the shared-inbox design. A tenant with no AppFolio thread is held no_pms_record, retried ten minutes, then held for good with one engineering alert; the list does not show it; it never falls back to Clara's line C63 C38renewals-only door: hours (the dispatch already carries kind and module); tenant thread start: days, robot repo
Tenant reply reaches PropFlowClara's own door text is filed even on a tenant threadTenant threads are held tenants_later: the tenant's "yes" is never filed and never wakes Clara; a teammate's AppFolio text to the tenant never stops her reminders C65hours to a day
Clara answers only where she shouldThe wake rule already requires Clara's own text to be the newest office-side message on the thread, so a tenant who texts first, or after a teammate, never wakes herNo "her last text was a renewal" guard, and the woken reply is labelled as a prospect'sin the same PR as the row above
Fede approves each replySupervised holds Clara's text and email replies on renewal threads; the woken reply re-enters the same pathThree carve-outs: urgent maintenance replies are never held; replies to staff are not held; a "general" reply off a renewal thread is not held. Clara's actions run before approval: marking renewed, stopping reminders, the "tenant countered" note to the officehours (words); a day (actions)

"Nothing leaks without me": what waits for Fede today, and after the minimum build

Message or action to a tenant or the officeWaits for Fede today (Renewals Supervised at WS)After the minimum build
Day-0 offer text, after the team approves the listno released by the list approvalyes build 2
Reminder texts (day 2, day 9)no same releaseyes build 2
Offer email to a tenant with no phoneno same releaseyes build 2
Clara's reply to a tenant on a renewal threadyes except an urgent maintenance replyyes; the urgent carve-out closes with decision D10
Clara's reply to a tenant on any other AppFolio threadn/a tenant threads never wake hern/a the wake stays limited to threads where her last text was a renewal
Marking renewed, stopping reminders, the "tenant countered" note to the officeno the tools act when the reply is draftedD10: words only (today) or actions too (a day of work)
Phone call to a tenantyes Supervised default "calls go to the team" means no callunchanged
AppFolio offer or application link made by the robotn/a the office sends the paperwork; no Supervised check exists on these two robot writesunchanged; the only path to a literal 100% is one per-company hold at the text door, the email seam, the voice door and the two robot writes (days)
Prospect texts at Western Slopen/a Leasing is its own moduleD7 decides whether the door moves them too

Minimum build, one PR each, in order

#PRSwitch?SizeProof rung
1Door scope per module: the company text door applies to renewal sends only when D7 says so; the dispatcher already carries kind and module, so this is a read in the door resolver, no new field. The wake rule reads the same scope: the mirror filer reads the raw company setting today (file-message.ts:263), so a renewals-only door must never wake Clara on a leasing threadthe existing company setting gains a scope; dark until Fede flips WShoursunit + Willows
2Supervised keeps the per-offer hold after the list is approved: the approved list re-renders each parked offer with the team's rent and term and leaves it pending for the reviewer; Live keeps today's releasenone (fix to live behavior)hoursunit + Fairhaven list
3List rows show "no AppFolio text thread, will not send": read the mirror for each tenant's phone at list timenonehoursunit + WS list dry run
4File tenant threads; wake only when Clara's last text was a renewal; (Fede, 2026-10-19: "yes, can we build a local proof of concept first or try at the Willows": a read-only local run over the Western Slope and Willows inbox copies first, result on this page, then one small PR and the Willows tenant try) place the reply on the renewal conversation; label the sender as a tenantnone; lifts the tenants_later hold under the existing mirror settinghours to a dayunit + Willows tenant
5Reminders skip a tenant a teammate already texted (Fede's rule 1), read from the filed thread at each reminder wakenonehoursunit + replay
6Willows live proof, tenant edition: offer in a tenant's AppFolio thread, the tenant's answer filed, Clara's held reply, approve, sent in AppFolio, STOP—a dayWillows
7Tenant sends on the door, two steps: (a) prove the tenant send shape with one captured tenant-page text at the Willows and allow the tenant party in the robot (prerequisite for build 6 too, since Clara's approved reply leaves through the same door); (b) a tenant thread start using the tenant page as the form source (AppFolio's own Text button; no guest card). With 47 of 59 people lacking a thread, (b) decides reachnone(a) hours plus one live capture; (b) about a day, robot repoWillows
8Meeting notes to the list (notes intake or transcript for a company with an open list runs the reply reader)nonehoursOct 27 dry run

Not on the list, already decided: the office sends the paperwork (C43), so no letter PDF and no AppFolio offer by Clara; the Oct 20 and Oct 27 dry runs (section 6) stay as planned. Also stale and fixed: the tracker row "blocked tenant text after approval tells nobody" was fixed Oct 13 (#19304); the plate's "hold until the policy arrives" is over (policy arrived Oct 7).

Proof of concept for build 4 (local, read-only, 2026-10-19 16:00 MT)

Fede asked for a local proof of concept before the tenant-thread code is written. A harness replayed the mirror copies of the Western Slope and Willows inboxes through the filer and the wake rule as if the tenant hold were lifted and the renewal guard added. Nothing was sent, no code pushed.C67

QuestionWestern SlopeWillows
Tenant messages held today707 on 245 threads; all would file onto 240 known people, none orphaned; 219 join 27 existing conversations, 488 open new ones, none a renewal conversation2 tenant-shaped threads
Rows that would wake Clara, today's rule with the hold lifted0 (Clara has never texted a tenant through the inbox there; all 33 of her inbox texts are on prospect threads). Nearest miss: one thread where her last text was a maintenance rating request from her own line, which the renewal guard blocks0
Rows that would wake Clara, with the renewal guard00
Renewal-window people with a thread20 of 67 in this later copy (the morning read said 12 of 59); 9 have more than mass texts; 3 have an open renewal; Clara spoke last for nonethe usual tenant test number has no inbox thread; a new one is needed for the live try
Risks the replay exposed193 of 245 tenant threads also carry a prospect or applicant, so the guard applies to tenant-only threads and mixed threads keep today's rule · 37 threads have two tenants on one phone (follow-up) · 6 threads would land on a person whose record lacks that phone · the mirrored copy of Clara's text is always an ordinary reply, so the guard must read the kind on the conversation the reply lands on, which means the reply must be routed to the renewal conversation while the renewal is in play · there is no daily label judge for held tenant rows (the gap map assumed one)

Rulings made by the session, not Fede (routine data work): route a tenant reply to the person's renewal conversation while the renewal is in play; guard only tenant-only threads; re-offer the 707 held rows as inert history. The small PR (build 4) started 16:10 MT with the POC as its spec; the Willows live tenant try follows the merge, with a fresh tenant-shaped number and an open renewal on it.

Four calls for Fede

#DecisionOptionsRecommendation
D7Decided (Fede, 2026-10-19 evening, by voice): the ONE company-wide switch, no renewals-only split. "I don't think we want some stuff going out on our line and some stuff going out on AppFolio… once we're ready, we're going to flip the whole company." Build 1 is dropped. Before the flip he wants: more end-to-end leasing-funnel runs with guest cards through the Willows on the door, an inspection of what the door has already proven end to end, and one production-readiness page (cutover for conversations and workflows in flight, side effects, Clara woken on every tenant and prospect reply in AppFolio, Situs Group). The flip at any customer stays his call. Readiness page: AppFolio door flip: production readiness (proposed, pending review). Which door for renewals at Western Slope this week(a) flip the company-wide AppFolio door and mirror now: leasing texts move too, and it is the switch on hold since this morning pending Clara in the shared inbox · (b) a renewals-only scope on the same door (build 1), leasing stays on Clara's line until the design is reviewed · (c) send renewals from Clara's line this week, AppFolio later(b): it is the use case Fede named, hours of work, and it leaves the shared-inbox decision where he left it
D8Decided (Fede, 2026-10-19 15:05 MT: "yes supervised should hold even after their reply"). After Kat and Jay approve the list, each offer still waits for Fede. Build 2 started the same hour.(a) yes while Renewals is Supervised (build 2) · (b) the team's list approval is enough, as today(a): it is what "supervised" promised, and the only way the first offers are seen before they leave
D9Decided (Fede, 2026-10-19 evening, by voice): build the tenant thread start now, abstracted behind the PMS adapter layer so it holds for Yardi and others; and yes to one captured test text at the Willows so the robot learns the tenant send shape. Both started the same hour (robot PR + app PR, build 7). Tenant sends through the door: today none work (robot refuses the tenant party); after step (a) the 12 with a thread work; the other 47 of 59 people (27 of 34 leases) need step (b)(a) held, shown on the list as "no AppFolio thread", the office texts them first or Fede sends from Clara's line by hand · (b) the offer leaves from Clara's line automatically · (c) build the tenant thread start first (days)(c) started now and (a) meanwhile: 47 of 59 people have no thread, so without the thread start the door reaches 7 of 34 leases; (b) breaks "they know it's the team"
D10Decided (Fede, 2026-10-19 evening, by voice): yes, everything waits. "If it's supervised it holds everything. I think that's cleaner." While Supervised, the office note, the renewed mark and stop-reminders wait with Clara's reply for approval; nothing moves until approved. Builder started the same hour. Do Clara's actions wait for approval too, or only her words?(a) words only: marking renewed, stopping reminders and the office note happen when the reply is drafted · (b) the office note waits with the reply; internal marks stay immediate · (c) everything waits (a day of work, new resume path)(b): the office note is the one outward-facing action; a misread yes then costs nothing outside PropFlow

Started 2026-10-19 15:10 MT: builds 2 and 3 (one PR each, in worktrees) and the local proof of concept for build 4. Builds 1 and 7 wait on D7 and D9.

PRs open 2026-10-19 evening (each merges on green under the standing grant; none turns anything on at a customer):

BuildPRWhat changesSwitch?State
2#21210At a Supervised building the approved list fills in the team's rent and term and leaves every offer and reminder waiting for the reviewer; the reply to the list reviewer now says "N offers are waiting for the Supervised reviewer" instead of "goes out as listed"; held offers never expire on the 24-hour timer. Live and Off unchangednone (fix)merged and live 2026-10-20 02:41Z (worker rebuilt). Fairhaven proof, read-only pass 03:20Z: the "before" is on record (the October list, approved Oct 16 under the old code, auto-approved its first offer and its Oct 18 reminder under the list reviewer's name 0.1 s after each was held, and the reminder was delivered to our bench line). The "after" ran Oct 20 14:11Z: one renewal started at Fairhaven for unit 305 (saga saga_4d2da627…); its first offer is held and pending for the Supervised reviewer, re-rendered with the list's $2,645 on 12 months, no approver recorded, no text sent (Twilio: 0 messages to the tenant's smoke number), no expiry date on the hold. Still to watch: the hold must still be pending at 14:12Z Oct 21, and the bench-line reminder due Oct 25 14:01Z must land held
3#21216List rows mark a tenant whose phone has no texting thread in the PMS inbox copy ("will not send through the PMS inbox"); nothing else changesnonereviewer 🟢; parked for the next batch train
4#21221Tenant threads are filed on the person's conversation (on the renewal conversation while a renewal is in play) instead of held tenants_later; Clara wakes on a tenant's text only when her newest office-side text on that thread was a renewal; the woken envelope says tenant. Finding while building: at a company on the PMS text door the dispatcher writes no conversation row, so the "last text was a renewal" guard never sees a kind there; follow-up #21214 (the door's send record keeps the kind, stacked on this PR, building now) is needed before a tenant reply can wake Clara at Western Slope. Also filed: #21212 co-tenants on one thread, #21213 filing the 707 held rows of historynone; lifts the hold under the existing mirror settingreviewer 🔴 only on an older test that still pinned the hold; fixed; follow-ups #21274 #21275 #21276
7a + 7b (robot)robot #580The robot now texts a TENANT: the tenant party is accepted, and a new route sends from the tenant record (AppFolio's own Text button) so a thread is started where none exists. Proven by two real texts from a Willows test tenant to a PropFlow-owned line on Oct 19 (19:0x MT): the tenant page uses the same send request as the guest card, differing only in the party label and the page name; AppFolio appends "Reply STOP to unsubscribe" to the first text; the second text lands in the same thread. Two inbox-send fixes came with it (first-text footer no longer reads back as unknown; a zero message cursor no longer silently passes the stale check)nonemerged and live in production (Oct 19, 7:3x PM MT)
7b (app)#21249A first text to a tenant with no AppFolio thread opens one from their tenant record (their lease at the building); the record wins over a guest card for a current tenant; prospects keep the guest card; AppFolio specifics stay in the adapter, core names no PMS. Fires only at a company on the door, only when no thread existsnone; improvement to the dark doorreviewer 🟡; merged 2026-10-20 02:3xZ; the Willows tenant leg (a renewal-style text opening tenant 1851's thread, the reply, the held reply, the approval) runs once it is live
D10#21257While Renewals is Supervised, Clara's renewal actions (the resident's yes or no to the workflow, stop-reminders, the escalation entry, the "tenant countered" office note, a term change) are written on the held reply instead of run; they run once, in order, when the reviewer approves and the reply goes out, and are dropped on reject or expiry. The reviewer's card says what approving also does. Live and Off unchangednone (fix to Supervised)reviewer 🔴 round 1 (a direct #alerts post; now an alert kind on the registry) and round 2 (one dedup key per conversation hid a second dropped answer; now keyed on the failed batch); third push waiting on the reviewer

What the Western Slope list would hold today (dry run, read-only, 2026-10-20 03:20Z)

Nothing opened, nothing sent. Renewals is Off at Western Slope (company and all 90 buildings), the texting route is still Clara's line, the AppFolio inbox copy is on. The numbers below are what the list code would produce if the company were Supervised.

11
offers on October's list, across 10 buildings; 7 ready, 4 flagged for an unpaid balance (still go out once the team approves)
9 / 2
tenants with an AppFolio texting thread / without one (marked "no texting thread in AppFolio"); none without a phone
8
more leases left off because the office already made the offer in AppFolio
26
on November's list (18 buildings; 23 with a thread, 3 without); 11 of them are October's if October never opens

Worth a look before the flip: every row offers the same rent as today, because every building's rule reads "up to $0 increase, 12 months". If Western Slope wants increases, the rent rules need numbers first. Reviewers on record: Jay Taylor and Kat Barker (the list email goes to the first). Two rows checked against the raw lease records (end date and rent) matched exactly. Raw output stays local in the session scratchpad (tenant names).

With D7 to D10 answered today: PRs 1 to 5 open Tuesday and Wednesday, the Willows tenant proof runs Thursday, and Renewals at Western Slope can flip to Supervised with the renewals door on Friday, Oct 23, after the Oct 20 dry run. Every offer and every reply then sits on the approval queue until Fede presses it. Sources: the code gap map, the Western Slope production read and the docs and transcript pass, all 2026-10-19, in the session's scratchpad (`door/renewals/`).

Overnight Willows run, 2026-10-20 04:30–05:00Z: the loop end to end on the test property (steps 2–5)

Building 45 at the Willows on Supervised, one test tenant (unit EVAL-101, phone ours), a hand-written meeting transcript. Nothing reached a tenant; every write is ledgered in the session folder.

StepResultWhat happened
2 · Transcript → decisionsPASSEVAL-101 read as renew, +$25, 12 months, with Jay's line quoted (9 s, nothing written). The "circle back next week" line held only its own row; the rest were still decided (#21343).
3 · List opensPASSOctober's list opened with 28 rows; the list email went to our reviewer mailbox only. Blocked at first by our own Oct 16 test list (one list per company per month); deleted our two test lists, dumped first.
4 · Reply, revise, approveApprove PASS, email edits FAIL"approve" with no quoted thread approved the list (EVAL-101 at $1,550 / 12 months, 27 rows struck). Five replies with an Outlook-style quoted thread recorded nothing: Clara re-read her own earlier question. The pasted transcript was refused whole because it contains a question.
5 · Offer held, Slack cardPASS (14:00Z)At 14:00:07Z the offer text was held, pending, $1,550 / 12 months, tied to the approved list, no expiry, not auto-approved; the card posted in the Willows test channel. Nothing reached the phone before approval. Per-offer holds send no reviewer email on purpose: the Slack card is the ping, with a link to the review page (no Approve button on the card itself; "approve" in the thread works for a platform admin).
6 · Approve → text through the doorPASSApproved by a platform admin at 14:10:56Z; the text left through the AppFolio door (message 1166439375) and reached our phone from the AppFolio texting number 13 s later. Nothing from Clara's own line.
7 · Tenant replies "Yes, we'll renew"PASS (rerun, 17:27–17:40Z)Three tenant replies on the AppFolio thread ("yes", "yes", "no") each woke Clara as a renewal reply (log line "reply on Clara's open thread: vendor routing skipped"). No vendor note on work order WILL-002145, nothing from Clara's own line. The renewal reader recorded the intent. Clara's reply was held under Supervised (holds eschold_99d58d7c…, eschold_c7113bd3…, eschold_e05c1924…); approved replies left through the door in about 12 s (AppFolio 1166675247 offer, 1166684861, 1166689273). Before: at 14:11Z the same reply went to the vendor lane and produced a false "Vendor status update" note.
8 · Office emails (staying goes to the leasing team; not renewing goes to the office with the notice instruction)PASS (r5, Oct 21 19:31–20:03Z, Fede approved 3 cards in Slack): yes → "please prepare the lease" email delivered to the test office mailbox 4 s after approval (SendGrid HaLEfXi3Sn2L6IQ24ZiPPA); no → "is not renewing" email delivered 2 s after approval (SendGrid s4pGdv4SRJ-lfPiGnMNeGg), notice line = "No notice period is on record for this building" (from code + live lookup, email body not opened). Each approved reply sent exactly once from Clara's line (renewals stay on Clara's line since #21569; the AppFolio texting line is leasing only).Before (r3, RED, rerun 17:27–17:40Z): Blocked by two new defects, fix PRs in progress. The "yes" was lost because the first approved reply failed to send and nothing retries it, so the "prepare the lease" email never fired. The "not renewing" office note was built correctly ("No notice period is on record for this building" at the Willows, which has none) but failed to send in the runner's process, and failed office emails are never retried. Rerun after both fixes are live, approving through the real path (Slack "approve" command or the website).
8 · RestorePASSBuilding 45 back off at 14:28Z, before the 14:30Z scan; workflow terminated; nothing pending from today. Three smaller findings filed as issues: offer text said "coming up on your lease end date" because the lease end was blank; the nightly 09:00Z test rig minted 7 real offer holds under Supervised (rejected by hand); a stale "delivery failed" flag stays on a delivered hold.

Defects found Oct 20 PM:

  1. An approved reply that fails to send is dead, and its recorded intent is lost.
  2. A repeated "yes" is not re-recorded, so "You're all set" went out with nothing recorded.
  3. Failed office emails land in a dead-letter list that nothing drains.
  4. The test phone +17202630905 answers Clara by itself: its Twilio webhook points at a voice agent, and a "Miracle Cleaners" auto-reply was filed as the tenant and raised a false escalation (the test guards blocked it). Needs disarming before the next text run.
  5. The test reset leaves the per-cycle claim and lease-end fields behind.

Defects found Oct 21 (r5):

  1. #21621: the test phone was matched as a vendor before a tenant, so the reply went to the maintenance lane; a 5-text loop with the test phone's auto-responder followed, stopped by switching Maintenance off at building 45.
  2. #21624: a "no" after a "yes" never ends the 14-day countersign wait (new, real).
  3. #21625: the Supervised hold is bypassed when the classifier labels a renewal-tool turn "other": three texts left unheld and the inline office pass-off failed, which raised the bake alert "Renewal action did not land" at 20:05Z (real).
  4. #21626: tenant replies land on the general text thread, not the renewal conversation.
  5. #21627: the "no" hold card omits "and tells the office".
  6. #21628: intent signals from a text are labelled "voice".
  7. #21629: Clara re-texted a wrong-number auto-responder three times before stopping.
  8. No issue (same as r3): the office pass-off can never land at the Willows, because its renewal contact is a test.local address and owner pages are blocked for sandbox.

Bugs found, fix PRs in flight (no switch, live on merge):

Two things the code does that the loop map did not say: a lease that surfaces after the month's list is approved skips the list and becomes a direct Supervised hold, which still pings the card; and a held offer with no list behind it closes as rejected after 24 hours with "Expired — not sent" posted in its Slack thread (never silent). A held offer tied to an approved list never expires.

Step 8 proven Oct 21 (2:03 pm MT). Steps 1–8 all pass on the live code. Before any Western Slope turn-on: fix #21625 (Supervised must hold everything, Fede's rule) and #21624 (a no after a yes must end the workflow). The per-building 'quiet hours off' setting was dropped by Fede on Oct 21 (PR #21567 closed unmerged): test sends run inside 8 AM–9 PM local. Lane handed to session 005 (document engine direction) on Oct 21.

11 · Update 2026-10-20: why so much got built and nothing is on, and the packet-first turn-on

Fede, 2026-10-20, after the Western Slope meeting (no recording): the biggest value for them is preparing the renewal packet; the north star is "they meet on Monday, they decide… Clara prepares the offer like we do at Camellia, fills everything, parks it, and tells them it's ready for review"; no Monday.com integration, ever; nothing hard-coded per customer; "why did I build so much and I feel like I'm not anywhere near being able to turn on". This section is that rethink, written with an Opus 5.5 pairing round at max thinking and a read-only pull of their real AppFolio renewals. Proposed — pending review

The short answer. On Oct 7 we cut the packet out of scope ("half of their properties don't have a template") and spent October making tenant texts safe: holds, approvals, a text door, a reply reader. The data says the reverse: the packet is one page with six blanks, five of them lease facts or the Monday decision; it is the slow, hand-typed job they value; and it should never reach a tenant until a person presses Send inside AppFolio (proven at the Willows first; the portal check is the gate). The texts leg, where every gate sits, reaches 12 of 59 tenants today. Turn on the packet first, with one gate (their Send click), and point texts at the tenants who have not signed, later.S5 S9 S10

11.1 How they do it today 11.2 Why so much, and nothing on 11.3 The model on one whiteboard 11.4 One engine for any customer's packet 11.5 What exists, what is missing 11.6 Minimum build and proof 11.7 Decisions for Fede 11.8 Tomorrow's meeting Sources

11.1 How Western Slope renews a lease today (from their real AppFolio records, Jul–Oct 2026, read-only)

flowchart TB
  subgraph A1["Before the yes"]
    direction LR
    M["Weekly renewals meeting\nJay, Kat, Jason, recorded\ndecides each lease and the rent"] --> B["Monday board\n146 lease rows, 12 statuses\nupdated by hand after each step"]
    B --> E["60 to 90 days out\nprice email from the Assistant PM login,\nthen follow-up texts and calls"]
    E --> Y["Tenant says yes\nby text or email, inside AppFolio"]
  end
  subgraph A2["After the yes"]
    direction LR
    P["Office builds the AppFolio offer by hand\none amendment, 6 typed fields\nsent in batches for e-sign"] --> R["Unsigned: 'resend' in batches\n(Sep 9, Sep 24, Oct 13)"]
    R --> C["Jay countersigns"]
    C --> K["Kat by hand: rent charge,\nmonth-to-month fee date,\nrent-increase date"]
  end
  Y --> P
  classDef hand fill:#fff4e5,stroke:#B45309,color:#5a3200;
  class B,E,P,R,K hand;
Orange: a person does it by hand today. The offer goes out only after the tenant's yes, 12–87 days before the lease ends (most 47–78; one outlier five months early). The board is the team's memory, not a workflow: 1 of 146 rows changed between the Oct 15 and Oct 16 exports.S1 S2 S9
175 · 5 · 0 · 7
in their AppFolio today: Eligible (all dates) · Out for Signing · Prepared not Sent · Completed. They never park an offer; they send right after the yes S9
19 + 10
leases ending in the next 90 days (Oct 2, Nov 6, Dec 9, Jan 1–18: 2), plus 10 Northridge month-to-month; then 10, 8, 10, 11 a month Jan–Apr 2027 S9
100 → 11 → 4 → 5 → 3
Monday board, the 146 rows with a lease-end date: No Contact Yet → In Contact → Prepare Renewal Offer → Out for Signature → MEC; side exits Move-out 4, Do Not Contact 5, Do Not Renew 2, Escalate 3 S2
5 + 1
typed fields on their one amendment: five come from the lease and the decision (today, original start, new start, new end, rent); one is free text, blank on 9 of the 11 offers opened (the other two: "credit one month rent free as renewal promo", "waive 1 pet fee through 12/1/2027") S3 S9 S10
Their packet, per propertyWhat the office actually sendsThe property's default in AppFolio
Situs-owned properties (single-family and small multi-family), Pomona Park, Courtyardone addendum, "AF Renewal Function: … RENEW (SIMPLE)" (an AppFolio addendum template, not a PDF form), on 11 of 11 recent offers; one term option (12 months on 15 of 17 recent offers, one 7-month, one 6-month); give-notice option on; rent flat or +$25 to +$150the same
Two other propertiesthe same one addendumdiffers: 12 addenda + 2 attachments at one; a pet addendum + the old simple amendment at the other. Building from the default would send the wrong packet
Northridgea whole new lease ("Northridge NEW LEASES" template, 11 addenda, 4 attachments); 10 tenants month-to-month todaya new lease, not a renewal amendment

Company settings: month-to-month option on, give-notice in the portal on, Renew by Default off (company-wide and at all 8 sampled properties), full signatures. No property sets a default renewal letter; whether a letter ever went with an offer: unverified. 9 occupancies across 8 properties checked.S9 S10

11.2 Why so much got built and nothing is on

CauseWhat happenedEvidence
1. The packet was cut on a premise the data does not supportOct 7: Jay, "building the templates is out of scope… the one page renewal could be in scope"; Fede, "step one could be not even send the contract, just send the communication… because half of their properties don't have a template". The one-page renewal Jay called in scope is the document on 11 of 11 recent offers; AppFolio's property defaults match what the office sends at 6 of 8 sampled properties and the office overrode the other 2 with that same page. The cut threw out the in-scope part with the out-of-scope part.levels page ruling log Oct 7; S9; S10
2. Every safety gate was stacked on the texts leg"Nothing leaks without me" became a hold on every message: module switch, policy rules, list approval, Supervised, Fede's per-offer hold, the door's shape check, the office emails. Seven gates before one text, for a leg that reaches 12 of 59 tenants and that the office already does by hand. The leg with no tenant contact at all, the parked packet, got none of the attention.section 10 gate table; S5
3. Built in Camellia's shapeCamellia is autonomous: Clara texts from her own line and the robot prepares and sends. Western Slope's whole conversation lives inside AppFolio, so each month a new door, filer or wake rule was needed before anything could be tried.sections 2, 10; S5
4. The ladder had no place to prove a customer-only shape, so the proof never ranJP&Co's templates have no typed fields, so the Willows cannot exercise the fill, and a sandbox in Western Slope's shape would need their templates in an AppFolio database we do not have. The fill gap was known on Sep 28; the cheap route (read their form, then one parked fill on Fede's word) was never taken after the Oct 7 cut, and the Willows was never used to prove parking, portal visibility and email, which needs no fill at all. Ladder fix: when no test environment has the customer's shape, the first live rung is one parked, never-sent write at the customer, on Fede's word.S4; S7; testing playbook
5. ProcessFive planned turn-on dates slipped (Oct 2 → 5 → 12 → 14 → 23); four lanes touch renewals; six pages and a PDF, about 110k words where the house rule is ~800; 189 + 264 renewal commits on main in Sep and Oct; the design changed four times (monthly list → weekly loop → per-offer hold → every offer and reply on Fede's queue), each change adding a gate, none removing one.one-doc 9/23; levels 10/3, 10/12; section 10; git log origin/main 46638b5; S10

The single cause that explains the most: we treated the packet as the hard part and the texts as the easy part. The packet is one page, only exists inside AppFolio, and is the hand-typed job they value; the texts are the part the office already does, and after Send AppFolio emails, reminds and collects the signature on its own (25 of 30 offers signed that way).S1 S9 S10

What was right, keep it: the decision engine (0 wrong actions on Camellia meetings, 74 of 81 clear rows right; section 7); a PMS-neutral renewal record with AppFolio behind an adapter; robot code that refuses unknown fields; the "who sends the paperwork" setting, which is exactly where the new value goes; the AppFolio text door, mirror and reply wake, proven at the Willows (section 10); Camellia live end to end.S4 S5 S10

11.3 The model on one whiteboard

flowchart LR
  D["DECIDE\nthe Monday meeting\nrent, term, concession, not renewing\ntyped on the renewal list\n(Clara pre-fills what the notes make clear)"] --> P["PAPER\nClara builds the packet in AppFolio:\nthe right documents, every blank filled,\nasks the office when unsure\nparks it: Prepared not Sent"]
  P --> G["THE ONE GATE\na person opens AppFolio,\nchecks the packet, presses Send\nafter the tenant's yes"]
  G --> A["AppFolio\nemails the offer, reminds,\ne-sign, Jay countersigns"]
  A --> L["Clara reads the status back daily\nprepared / out for signing / signed / notice\nthe renewal list replaces the Monday board"]
  L -.-> D
  T["TELL (later)\nClara's texts in the tenant's AppFolio thread\nfor the ones who have not signed\n002's comms hold: Fede approves each message"] -.-> A
  classDef gate fill:#e8f5e9,stroke:#2e7d32,color:#1b4d1e;
  classDef later fill:#eef0fe,stroke:#4F46E5,color:#1E244A;
  class G gate;
  class T later;
Three jobs. Decide is theirs. Paper is Clara's and never reaches a tenant. Send is the one gate, in their system, no new screen. Tell is 002's loop (section 10) and comes after paper is live.
Gate today (section 10)On the paper legWhy
Renewals module Off / Supervised / Livereplaced by one new value on the existing "who sends the paperwork" setting: Clara prepares, office sends; default off; Fede turns it ona new customer-facing capability: setting, default off (rollout rule)
Eligibility rules (balance, late payments)facts shown on the list, not a gatethe meeting decides; "renew at zero balance" is their rule
Monthly list-approval click (Jay or Kat)delete for paperthe decision typed in the meeting is the approval; a click that confirms what the system already knows is a manual-decision screen. After each build Clara sends one note per batch ("N packets ready", what she understood, her questions); it releases nothing. D8's intent (Oct 19) stays: nothing reaches a tenant until a person says so; the hold moves from Fede's queue into AppFolio's "Prepared not Sent", held by Western Slope's staff. Texts keep D8 and D10
Supervised (every message held)not on this legno tenant message exists until Send
Fede's hold on each offerdelete for paperthe parked packet plus their Send is the hold; Fede is not Western Slope's reviewer
Text-door shape checknot on this legno text

Two weak points to close at the Willows before any customer: a parked offer must be invisible to the tenant (portal and email) and must fire no AppFolio reminder; AppFolio's help says both happen only at Send, but neither is proven on a live portal. Two rules in code: Clara never prepares where an offer already exists, and reads status back daily; the office's own offer wins.S8 S10

11.4 One engine for any customer's packet, nothing hard-coded

Clara fills the form the way a new hire would: copy what the office did last time, use the lease and the meeting for the values, ask when unsure. All of it is company data, never a code module per template (today Western Slope's six blanks live in a template-specific robot module, and any other customer's blanks would be refused).S4 S10

PartRuleWestern SlopeCamellia
Which documentsthe property's last completed offer; else the company's usual document for that kind of property; else ask. Household changes (someone joins or leaves) are a decision input, since they change the amendmentthe one-page amendment on 11 of 11; Northridge (a whole new lease), the Section 8 buildings and voucher tenants (the amendment carries the full contract rent while AppFolio's offer holds the tenant's share: one recent offer shows $2 against $1,300) stay with the office in v1one PDF form plus the letter, as the robot does today
Each blanka fact (from the lease), a decision (from the meeting), a standing answer (the company's rule), or an ask (one line to the office outside AppFolio; Clara fills the answer, then parks). Never park a packet with a blank for staff to typetoday's date, original lease start, new start, new end: facts (one holdover rule for month-to-month tenants); rent: decision, default flat; special provisions: decision, blank on 9 of 11no blanks
Options and deadlinefrom the decision and the company's standing answerone option (12 months); deadline rule to be asked (their offers: 3–4 weeks before the new term on 11 of 17, the rest at or within a week of the lease end)as today
Park or sendthe "who sends the paperwork" settingClara prepares, office sendsClara prepares and sends
Learningno confirmation screen (about 90 properties at Western Slope would mean 90 clicks); the Send review is the check; Clara reads back what was actually sent and learns from any change

11.5 What exists, what is missing

The paper leg. Labels: proven at the Willows / built, unproven / missing.

PieceStateEvidence
AppFolio's park state with a Send buttonproven at the Willows, by handOct 20, occupancy 986: fill → Review Renewal Offer → close the preview; the offer waits as "Prepared not Sent" with the rent kept; Send Renewal Offer is a separate click; a mid-form reload loses the form; 4 test offers made and cancelled, nothing sent S7
Prepare and stop, PDF-form method (Camellia's)proven at the Willows, scriptrobot scripts prepare-only and retry-prepared S4
Prepare, Western Slope's method (addendum templates)built dark Sep 28, unprovenrobot #435 (field mapper) + #439 (write path); recorded once at JP&Co with an addendum that had no blanks; never run at Western Slope S4
Prepare and stop, Western Slope's methodmissingthe path always sends after preparing; only a no-write dry run exists S4
Fill the six blanksshape confirmed read-only Oct 20; a fill with values still unproventheir Prepare Renewal Offer page is a React app that POSTs JSON to /prepare_renewals with manual_merge_fields keyed by field id (64, 65, 66, 67, 68, 74), exactly the shape the robot guessed; the month-to-month option carries its own copy of the six fields; a field left blank gets a "will be blank" warning box, and Continue re-sends with ignore_warnings. Never sent with a value anywhere: JP&Co's templates have no typed fields, so the Willows has nothing to fill S4 S7 S11
Concession text, app → robotmissingthe app's input to the robot has no field for it; the mapper accepts one S4
Start and deadline ruleswrong for themrobot: new term = lease end + 1 day (a month-to-month tenant whose lease ended 7/31/2025 renews from 10/1/2026); deadline = today + 30 (their offers: 3–4 weeks before the new term on 11 of 17, the rest at or within a week of the lease end) S4 S9 S10
Original lease start (field 74)needs their rulingthe form leaves it blank; two dates could fill it (the original lease start, which equals move-in, or the current term's start); the robot sends the current term's start, the office typed the first signed lease's start on 9 of 11 (the two differ by two years at one occupancy, by a year at the captured one) S4 S10 S11
Robot request vs their form (from the capture, untested)five deltasthe robot hard-codes the renewal letter on at Western Slope while their form defaults it off (one line); it sends no addendum and no fields for the month-to-month option while the form sends both; it sends the insurance requirement off while the form sends it on with the $100,000 plan (a $10.50 monthly charge in the preview); it sends dates as YYYY-MM-DD while the form sends timestamps or MM/DD/YYYY (JP&Co worked with timestamps; date-only unverified); the deadline box pre-fills with the current lease end, the robot uses today + 30 S4 S11
Document choicebuilt on property defaultswrong at 2 of 8 sampled properties; cannot do Northridge S4 S9
"Prepared" read back onto the listmapped, not fedthe app maps Prepared Not Sent to "prepared"; nothing feeds it from AppFolio (002: nothing in its lanes reads it) S5 S10
"N packets ready for review" note to the officemissing, small

The texts leg, per session 002 at 21:00Z Oct 20 (its PROVEN / UNVERIFIED labels kept). Not needed for v1.

LegStateProof
Text in the tenant's existing AppFolio threadmergedPROVEN at the Willows Oct 20: held offer approved → door → AppFolio message → Twilio. Never sent at Western Slope (module Off). 12 of 59 tenants had a thread on Oct 19; the Oct 20 dry run found threads for 9 of 11 October and 23 of 26 November leases S5
First text to a tenant with no threadmerged Oct 20robot: two real texts from a Willows test tenant Oct 19 (robot #580); app path (#21249) end to end at the Willows: UNVERIFIED S5 S6
Tenant's reply wakes Clara, intent recordedmergedPROVEN at the Willows Oct 20 via the PMS mirror (#21447): "staying" and "not renewing" recorded; counter-offer and "not about renewal": UNVERIFIED S5
Email through AppFolionot builttenant email leaves Clara's own mailbox, not AppFolio S5
Office emails after a yes or no (overnight step 8)fixed, unprovensection 10, morning verdict; #21505 and #21507 live 21:43Z; rerun needs Fede at Slack to approve three test cards S5

11.6 Minimum build and proof (no PR before Fede's decision)

#PieceSwitch?Size
1App: decision fields on the renewal list (rent, term, concession text, not renewing, office builds) and the new setting value "Clara prepares, office sends"the setting value, default offa day
2Robot: prepare and stop for the addendum-template method; a real fill of the blanks; a check that no blank is left empty; read the state of a parked offer; a reliable cancel for rebuildsnonetwo days
3App: document choice (copy the last offer, fall back, ask), concession text to the robot, holdover start and deadline rules, read-back of AppFolio status onto the list, the "N packets ready" notenonetwo days

About a week for one builder plus the proof runs; an estimate, not a promise. Cut by proof: three PRs, each dark and mergeable alone.

  1. A test property in their AppFolio (D13a): one unit, one fake tenant, portal login ours. There: prepare and park with their templates, check the portal and inbox show nothing and no AppFolio reminder fires, send from a staff login, confirm the email arrives, the status reads Out for Signing and our list shows it. Until it exists, the Willows can prove parking with the PDF-form prepare-and-stop script but not the fill (JP&Co has no typed fields) and not the portal (no test tenant login).
  2. Capture the wire shape, read-only: done Oct 20 (their form opened by GET, its code read, every non-GET blocked, nothing submitted). The six blanks go out as manual_merge_fields keyed by field id, the shape the robot already sends; the five deltas above are the robot changes for PR 2. What a parked write still has to prove: that AppFolio accepts the values and the document shows them.
  3. Replay, read-only: for their recorded offers (11 previews read, about 63 recorded), does Clara pick the same document and the same six values? Target: identical apart from date format and the office's own typing slips.
  4. First fill at the customer: one Western Slope lease they pick, prepared by Clara and parked, never sent; they review it before pressing Send. Two conditions: their write lock is lifted for that one call only, and the deadline sits far enough out that AppFolio's "7 days before the deadline" reminder cannot fire before they review (unless step 1 shows reminders skip parked offers). A write at the customer: Fede's call (D13).
  5. Then the batch: leases ending in December (9) are the first Clara can own; the office has already made the November and December offers (5 + 6). At their median lead of 56 days, those packets are built in the first week of November. Northridge's 10 month-to-month tenants stay with the office.S9 S10

The smallest thing the customer would feel: after the Monday meeting, Kat opens AppFolio and that week's renewal packets are already built, every blank filled, waiting in "Prepared not Sent" with a note from Clara saying which ones.

11.7 Decisions for Fede

Only D13 (the test property in their AppFolio, asked for tomorrow) blocks the proof; nothing blocks the build. The rest confirm what is recommended.

  1. D11 · When does Clara build the packet? (a) Recommended: when the Monday list says "renew at $X"; the office presses Send after the tenant's yes, their order today, and paper never waits on texts · (b) only after the tenant's yes is recorded, which chains the packet behind the texts again · (c) before the meeting at default rent, and the meeting edits, which needs rebuilds and a cancel that is a known gap.
  2. D12 · Switch and gates for the paper leg. (a) Recommended: one new value on the existing "who sends the paperwork" setting, default off, Fede turns it on; delete the list-approval click, Fede's per-offer hold and Supervised for this leg (changes D8's scope for paper only; texts keep D8 and D10) · (b) same switch, keep Fede's hold on each parked packet for the first week · (c) keep the Oct 23 plan: Supervised, every offer and reply on Fede's queue.
  3. D13 · Where the first real fill happens. (a) Recommended (Fede, Oct 20 evening): a one-unit "ZZ TEST" property inside Western Slope's AppFolio, like the Willows at JP&Co, with a fake tenant whose portal login is ours; asked for in tomorrow's meeting, created by us with their robot login on their OK (one billable unit for them, nobody on their staff types anything). It proves the fill on their templates and the portal check on the same day, and gives the ladder the sandbox rung in the customer's shape it lacked · (b) one real lease they pick, prepared and parked by Clara, never sent, reviewed by them before Send (a write on a real tenant's record; no portal check possible) · (c) six test blanks in JP&Co's AppFolio (an account-wide write at another customer).
  4. D14 · Which documents. (a) Recommended: copy the office: the property's last offer, then the company's usual document, then ask; Northridge and Section 8 stay with the office · (b) the property's AppFolio defaults, as the robot does today (wrong at 2 of 8, cannot do Northridge) · (c) ask Western Slope to fix their defaults first (asks the client to type into AppFolio).
  5. D15 · Where the blank rules live. (a) Recommended: company data (fact / decision / standing answer / ask), drafted by Clara from past offers, no confirmation screen, the Send review is the check · (b) code per template, as today · (c) the office confirms a recipe once per property (about 90 clicks).
  6. D16 · Texts and ownership. (a) Recommended: pause texts at Western Slope until paper is live, then point them at the tenants who have not signed; one lane owns Western Slope renewals end to end; this page is the one page · (b) keep texts on the Oct 23 track in parallel · (c) drop texts at Western Slope.
  7. D17 · The Monday board. (a) Recommended: the renewal list replaces it; seed it once from the Oct 16 export file, every row including the expired-lease groups where the month-to-month holdovers sit (10 move-outs across all rows, Do Not Contact 5, Do Not Renew 2, Escalate 3), matched to an AppFolio lease by property and unit, never by name, an unmatched row becomes a one-line question, so Clara never prepares those; after the seed the list is the record; no connector, ever · (b) no seed, the meeting re-decides · Connectors (Monday, Google Drive) as company context: not now; a connector earns a place only when a named blank cannot be filled without it, and none qualifies today (rent is flat by rule; AppFolio holds the documents, lease facts, past offers and status).

11.8 Tomorrow's meeting with Western Slope: the advice and the six questions

The advice: the minimum to get renewals off the ground is the packet. After your Monday meeting, Clara builds each renewal packet in AppFolio and parks it; you check it and press Send, as today. Nothing changes for your tenants. Next: Clara reads AppFolio back so the board goes away; then she chases the ones who have not signed; then the after-signing bookkeeping (rent charge, month-to-month fee date, increase date). Questions the data cannot answer:

  1. Build the packet right after the meeting and hold it until the tenant says yes, or only after the yes?
  2. Who reviews and presses Send, and how do you want to be told that packets are ready? And may we add a one-unit test property to your AppFolio (like at JP&Co) so Clara prepares packets there before touching a real lease?
  3. Date rules: the deadline to respond (your recent offers use about 30 days before the new term on most and the lease end on some); a month-to-month tenant's new start (the 1st of the next month?); a lease that ends mid-month (extend to month end? your example today typed 1/31/28 in the amendment and 01/15/2028 in the offer); and "Original Occupancy Lease Start Date" on the amendment: the first lease's start (move-in) or the current term's start?
  4. When someone joins or leaves the household, do you use the add or remove amendments, and will the Monday decision say so?
  5. Which ones do you keep building yourselves for now: Northridge (a whole new lease), the Section 8 buildings, voucher tenants (the offer holds the tenant's share, the amendment the full rent)?
  6. Which decisions from the meeting should Clara pre-fill from the notes, and which do you want to type yourselves?

Sources for section 11

12 · For the Oct 21 meeting: simplify first, then automate

This section is written to be shown on a screen to Western Slope. It holds nothing internal: three pictures, two tables, one checklist. Proposed — pending review (Fede, Oct 20 night: "helping the customer simplify this first before we automate"; "even the humans are confused with the amount of stuff"; "we don't have to do all the properties at once").

12.1 Today 12.2 The simplified flow 12.3 Where the complexity goes 12.4 Start with the easy properties 12.5 AppFolio setup audit 12.6 What we ask tomorrow 12.7 How we can help 12.8 For Fede only

12.1 How a renewal happens today (nine steps, seven by hand)

ONCE TO GET THE YESA decision or the tenantBy hand1Weekly meetingDecide each leaseand the rent2Update theMonday board146 rows, 12 statuses3Price email60 to 90 days out4Follow-up textsand callsUntil the tenantanswers5Tenant says yesONCE MORE FOR THE PAPERWORK6Build the offerin AppFolioRemove the extraaddenda, then type6 to 30 fields7Send for e-signIn batches8Chase unsignedResend in batches9Jay countersignsNew rent posts itself.Month-to-month feeand increase date:typed by hand7 of 9steps done by hand
Seven of nine steps are done by a person. The offer is built only after the tenant’s yes, so every lease is handled twice. S2 S9

12.2 The simplified flow (what we propose for Western Slope)

ONE PASS · NO WAITING FOR THE YESClaraYou1Weekly meetingDecide each leaseand the rent, onthe renewal list2Clara buildsthe offerRight documents,fields filled in3SendYou press Send,or Clara sends4Tenant signsIn the portal, withreminders fromClara and AppFolio5CountersignStays with Jay6New rent postsAppFolio posts it;Clara updates thelist and fee dateYou press SendClara sendsTo startWhen you’re comfortable2 of 6steps done by handwas 7 of 9
Two hand steps instead of seven. The decision is made once, in the meeting. S5 S7

12.3 Where the complexity goes

TODAYSIMPLIFIEDNorthridge packet1 lease + 16 addenda + 4 attachmentsAbout 30 typed fieldsSame documentsOnly the fields that change are typedSimple homes packet1 addendum, 6 typed fieldsAsked twice, so 12 blanks per offer1 addendum, 1 typed fieldThe special terms, usually blankRenewal offerOpens with the wrong documentsAt some properties; you remove them by handOpens cleanEach property’s default set onceTrackingMonday board146 rows, 12 statuses, by handThe renewal listKept by Clara, read by youRemindersResend in batches, by handFrom AppFolio and ClaraAfter signingMonth-to-month fee and increase dateTyped by handPosted by Clara
The packet, the typed fields and the reminders are AppFolio setup, not software. How many typed fields can fill in on their own is checked on one test offer first. S3 S9
Who simplifies whatIn AppFolio setup (we set it up, with your OK)In the team's processClara takes over
The packetEach property's default renewal packet set once, so "Prepare Renewal Offer" opens with the right lease or addendum, the right attachments, nothing to remove. Fields that never change move into the template text; fields that come from the lease auto-fill.One packet shape per property type, decided once in the meeting, not per tenant.Builds it from the decision on the list.
The yesResponse deadline and give-notice option set as defaults, not typed each time.Stop waiting for the yes before building. The offer is the ask; the tenant signs or replies.Nudges the tenant who has not signed; records "staying", "leaving", "wants to talk".
The trackingNothing to set.Retire the Monday board for renewals; the meeting works off the renewal list.Keeps the list current from AppFolio's own status.
After signingAppFolio posts the new rent itself once the offer is countersigned (its help: "the associated rent charges for that lease option will populate"). The month-to-month fee is the hand step.Countersign stays with Jay.Posts the month-to-month fee date (later step, after the packet is live).

The moment from the meeting where Kat opened the lease, removed addenda, and did not know how to save and come back: AppFolio can save an offer unsent. "Review Renewal Offer", then close the preview; the offer waits under "Prepared not Sent" and Send is a separate click (checked by hand at our test property, Oct 20). That is a training note, not a build. S7

12.4 Start with the easy properties

TierPropertiesWhat AppFolio pre-fills when you click Prepare Renewal OfferWhat the office actually sendsWhat has to happen first
1 · start hereThe scattered single-family homes (7 sampled), Pomona Parkthe one renewal page (6 typed fields); one Pomona tenant pre-fills 12 addenda carried over from their original leasethe one renewal pagenothing in AppFolio; Clara builds from the list
2 · after a five-minute setup fix239 S Elm, 1009 Colorado; Ember Estates, BCIE and three Situs Grand Junction properties (no renewal yet)Elm: 12 addenda + 2 attachments, including a retired "ZZ OLD" pet addendum. Colorado: an old duplicate amendment + a pet addendum. The never-renewed five: 12–13 move-in addenda + 2 attachmentsthe one renewal page (Elm, Colorado); nothing yet (the five)set the property's renewal default to the one page, retire the old duplicates, with their OK
3 · laterNorthridge; Lincoln and Courtyard (Section 8, the office keeps these)Northridge: the NEW-LEASES template + 11 addenda + 4 attachments. Its own "RENEWALS – Lease Term" and "RENEWALS – Month to Month" templates exist but are not hooked upNorthridge: a whole new lease, 16 addenda, 4 attachments, about 30 typed fields (Fede's screenshots)hook up the renewal templates, cut the typed fields to the ones that vary; Section 8 stays by hand

All 11 recent offers that could be opened used the same one-page amendment, no PDF form, no attachment. The pre-fill is the property default plus whatever addenda the tenant's original lease carried, so a clean property default alone does not always shrink the packet. Lincoln was not sampled. S9 S12

1Start hereScattered single-family homesPomona ParkNothing to change.Clara builds each offer from the list.2After a five-minute setup fix239 S Elm1009 ColoradoFive never-renewed propertiesSet the renewal default to the onepage and retire the old duplicates.3LaterNorthridgeLincoln and Courtyard (Section 8)Hook up Northridge’s own renewaltemplates and cut the typed fields.Section 8 stays by hand.HOW WE HELPWE DOSet up your AppFoliorenewal defaultsYOU DOSay OK, propertyby propertyWE DOTest the whole packet ona one-unit test propertyin your AppFolioYOU DONothingWE DOAfter your meeting, Clarabuilds each offer andleaves it waitingYOU DOReview it andpress SendWE DOClara keeps the renewallist and reminds tenantswho haven’t signedYOU DORead the list insteadof the board
Not every property at once. The scattered homes and Pomona Park go first; Northridge and the Section 8 buildings stay with you until those run clean. S9 S12

12.5 AppFolio setup audit

What's good: every recent renewal we could open went out as the same single page. What's confusing: AppFolio still opens extra documents at some properties, and the library around that page holds many old copies. What we'd change: make that page the default wherever it's what you send, clear out the old copies, and do Northridge last, together.

THE LIBRARY 5 lease templates: full leases, 3 for Northridge 5 lease templates full leases, 3 for Northridge 44 addenda: extra pages; 8 old or duplicates 44 addenda extra pages; 8 old or duplicates 43 old PDF forms: none used on a recent renewal 43 old PDF forms none used on a recent renewal 4 attachments: radon + lead paint, English + Spanish 4 attachments radon + lead paint, English + Spanish 1 page, the one-page renewal amendment, went out on all 11 recent renewals we could open 1 page is what actually goes out on every recent renewal we could open: 11 of 11 PROPERTY BY PROPERTY Clean Step 1 · start here AppFolio already opens what you send Scattered homes (7 looked at): AppFolio opens the one renewal page, the office sends the one renewal page, 6 typed blanks. Scattered homes 7 homes looked at AppFolio opens 1 You send 1 Typed blanks 6 Pomona Park: AppFolio opens the one renewal page for 2 of 3 leases looked at; the third opens 12 addenda and 2 attachments. The office sends the one page, 6 typed blanks. Pomona Park One of 3 leases opens 14 documents AppFolio opens 1 You send 1 Typed blanks 6 Courtyard: AppFolio opens the one renewal page and the office sends it, 6 typed blanks. Section 8 renewals stay by hand. Courtyard Section 8: renewals stay by hand AppFolio opens 1 You send 1 Typed blanks 6 5-minute fix Step 2 AppFolio opens extras; a small setup fix 239 S Elm: AppFolio opens 12 addenda and 2 attachments, one of them a retired pet addendum. The office sends the one renewal page, 6 typed blanks. 239 S Elm Includes a retired pet addendum AppFolio opens 14 You send 1 Typed blanks 6 1009 Colorado: AppFolio opens an old copy of the renewal page and a pet addendum. The office sends the one renewal page, 6 typed blanks. 1009 Colorado An old renewal copy + a pet addendum AppFolio opens 2 You send 1 Typed blanks 6 Ember Estates, BCIE and three Situs Grand Junction buildings: AppFolio opens 12 to 13 move-in addenda and 2 attachments. No renewal yet; typed blanks to confirm together. Ember Estates, BCIE + 3 Situs Grand Junction buildings AppFolio opens 14–15 You send no renewal yet Typed blanks to confirm together Later, together Step 3 The biggest packet, and Section 8 cases Northridge: AppFolio opens the new-lease template, 11 addenda and 4 attachments. The office sends a full lease, 16 addenda and 4 attachments, about 30 typed blanks. Northridge Its renewal templates aren't hooked up AppFolio opens 16 You send 21 Typed blanks about 30 Section 8 renewals at Lincoln and Courtyard stay by hand with the office for now. Lincoln's setup is to confirm together. Section 8 renewals Lincoln and Courtyard Stay by hand with the office for now Lincoln's setup: to confirm together How to read a card AppFolio opens: what's in a new offer You send: what the office sent Typed blanks: boxes filled in by hand, doubled (12) when month-to-month is on
Start on the left: those properties already work. Each card compares what is already in a new offer when you click Prepare Renewal Offer (AppFolio's button that starts a renewal) with what the office actually sent. The one page is the one-page renewal amendment, which AppFolio calls "AF Renewal Function: RENEW (SIMPLE)". Addenda are extra pages added to a lease; attachments are fixed PDFs such as the radon and lead-paint pamphlets; typed blanks are the boxes filled in by hand on each offer (AppFolio's "manually entered fields"). Counts are from your AppFolio on Oct 20; Northridge's come from screenshots of its renewal form. S12

What we'd change, with your OK

What we'd changeWhy it helps youWho does itTime it takes
Step 1 · start here  The easy properties: scattered homes, Pomona Park, Courtyard
Make the one renewal page each property's renewal default (AppFolio's property "Lease Settings").Locks in what already works: every offer starts with that page.We do itAbout 5 minutes a property
On one offer we save without sending, check whether AppFolio fills the new dates and rent.If it does, 6 typed blanks become 1 or 2.We do itAbout 30 minutes, once
Stop ticking month-to-month by default, unless you offer it on every renewal.AppFolio then asks for the 6 blanks once, not twice.You decideAbout 5 minutes
Pomona Park: find out why one lease opens 12 extra addenda; decide if renewals keep them.No surprise pages when that lease comes up for renewal.TogetherAbout 15 minutes
Step 2 · 5-minute fixes  239 S Elm, 1009 Colorado, five newer properties, and a library tidy-up
239 S Elm: make the one renewal page its default; retire the "ZZ OLD" pet addendum.Offers should open with the one page, not 14 documents to remove.We do itAbout 5 minutes
1009 Colorado: swap the old renewal copy and the pet addendum for the one page.Offers should open with the one page instead of an old copy.We do itAbout 5 minutes
Retire the 4 templates marked old or "do not use", and 4 duplicate amendments.About 36 addenda left, and one clear renewal page to pick.We do itAbout 15 minutes
Archive the PDF renewal forms made for a single tenant (2024 to early 2025).Your forms list shows only what you still use.You decideAbout 15 minutes
Ember Estates, BCIE, 3 Situs Grand Junction buildings: set the one page as default now.Their first renewals should open with one page, not 12–13 move-in addenda.We do itAbout 5 minutes a property
Step 3 · later, together  Northridge, and Section 8
Lincoln and Courtyard: agree which Section 8 renewals stay by hand.Nothing changes in AppFolio; everyone knows which leases stay manual.You decideAbout 10 minutes
Northridge: confirm its two renewal templates are current, then make them the default.Renewals start from renewal paperwork, not the new-lease template.TogetherAbout 30 minutes
Northridge: go through its 30 or so typed blanks; keep only what changes per lease.Fixed items like keys and carport become text; lease facts fill in themselves.TogetherAbout an hour
Northridge: fold the fixed policy addenda into one; keep the attachments renewals need.Far fewer pages for the tenant to read and sign.TogetherAbout an hour
Any time  Company-wide rules
Pick one rule for the response deadline; AppFolio sets it offer by offer.The date shows in the tenant portal, with a reminder 7 days before.You decideAbout 10 minutes
Pick one month-to-month fee rule; set it as a default if AppFolio allows.No more typing the $150 fee by hand as a future charge.You decideAbout 10 minutes
"Renew by Default": we'd check with you whether Colorado law and your policy allow it.AppFolio rolls a tenant who never answers onto an option you choose.You decideAbout 5 minutes to turn on, if yes
If your plan includes "Bulk Renewals", try it on one easy group of properties.AppFolio prepares many offers in one pass; you send when ready.TogetherAbout 30 minutes

Times are our estimates. Every item is a setting in your AppFolio, not software, and template edits apply only to offers made afterwards. S12

Things to confirm together

Everything here is a setting in your AppFolio, so you can change it yourselves, or we can make the changes for you or with you on a call, starting with the easy properties. Nothing changes until you say yes, and removing an old template never touches a signed or pending lease.

12.6 What we ask tomorrow (four questions)

  1. May we set each property's default renewal packet so "Prepare Renewal Offer" opens clean? (Tier 2 first.)
  2. Can we build and send the offer right after your meeting decision, instead of after the tenant's yes? If you want a look first, Clara leaves it waiting and you press Send.
  3. May we add a one-unit test property to your AppFolio (like at JP&Co) so Clara proves the packet there before any real lease?
  4. Which properties first: the scattered homes and Pomona Park? Northridge and Section 8 stay with you for now.

Timing note for the meeting: Colorado's 2024 for-cause rules are summarised by law firms as: for tenancies of 12 months or more, a tenant refusing reasonable new terms counts as grounds only if those terms were offered 90 days before the lease ends. Deciding at 60 days gives that up. If that reading holds, the meeting decides at about 120 days out and the offer goes by about 100. From law-firm and news summaries; the statute text itself is unverified and a Colorado attorney should confirm before any template ships. S13

12.7 How we can help (we are your partners in this)

We doYou doWhen
Set up your AppFolio renewal defaults so Prepare Renewal Offer opens clean at every property, retire the old duplicate templates, hook Northridge's own renewal templates up. We make the changes with you on a call, or on our own with the Clara login once you say which.Say yes to the list in 12.5, property by property.This week
Add a one-unit test property to your AppFolio and prove the whole packet there: every field filled, the offer parked unsent, the portal checked. Nothing touches a real lease until that passes.Nothing.This week
After your Monday meeting, Clara builds each packet from what you decided and leaves it waiting. You press Send. When you are comfortable, Clara sends.Decide in the meeting, review the parked offers, press Send.Start with the scattered homes and Pomona Park
Clara keeps the renewal list current from AppFolio's own status, reminds the tenants who have not signed, and records who is staying, leaving or wants to talk.Read the list instead of the board.As soon as the first packets go
Northridge and the Section 8 buildings stay with you until the simple ones run clean; then we cut Northridge's typed fields down together.Keep doing those by hand for now.Later

What you told us, and what we would do about it

You saidWhat we would do
"Our leasing templates are still an open item."Every recent renewal already goes out on one page, the renewal amendment. We set it as the renewal default at each property, so the open item is closed for renewals before the lease rewrite is.
"Building the templates is out of scope. The one-page renewal could be in scope."Agreed. We start with the one page: Clara fills it in, you press Send.
Ten templates and some fifty addenda nobody can explain.We list them with you and retire the duplicates and the "do not use" copies. One renewal set per property type.
"We use the leasing function for our renewals, so the renewal reports don't work."Renewals built on the Renewals screen show up on AppFolio's own renewal reports and reminders. We switch the first properties over with you.
Updating rents in AppFolio is manual, property by property.Send us the sheet. We load it, with your OK on each property.
"We would have to see it first."Nothing goes out unseen. Clara builds the offer and leaves it waiting in AppFolio; you review it and press Send. Clara only sends when you say so.
You are renewed through February, so there is nothing to send until December.That is the window. November is for the setup clean-up and a one-unit test property; the first Clara-built offers go to you in December, for March.
"Starting over from scratch is my dream."We do the clean-up with you, property by property, starting with the easy ones.

Their words come from our calls with them (Sep 9, Oct 7, Oct 14) and the Oct 20 meeting. S15

Two things you can use tomorrow without us: an offer can be saved unsent ("Review Renewal Offer", then close the preview; it waits under "Prepared not Sent"), and Colorado's for-cause rules reward deciding earlier (12.6). S7 S13

12.8 For Fede only (not for the screen)

  1. D18 · Prepare and send without waiting for the yes. (a) Recommended: yes, the Camellia process, same every time; the only exceptions are the list's "do not contact", "not renewing" and "balance" holds. No conditional "build only after the yes" step: it doubles the handling and is the step they forget. (b) Build after the yes only, as they do today. (c) Build at the meeting, park, send after the yes (two gates, more to remember).
  2. D19 · The careful-send machinery. (a) Recommended: keep exactly one gate, the "who sends the paperwork" setting (Clara sends / office presses Send); do not build the per-offer hold or the list-release step for the packet. Texts keep 002's Supervised hold until the packet is live, then it is reviewed for removal (one follow-up, no new work tonight). (b) Keep everything built and add the packet behind it. (c) Remove the texts hold now too.
  3. D20 · Simplify first. (a) Recommended: the AppFolio setup changes in 12.5 are offered in the meeting and done by us on their OK, before the first Clara packet; they also make Clara's job smaller (a clean default = nothing to override per property). (b) Build around their current setup as it is.

What they actually said, with dates (raw transcripts; for you, not the screen)

DateReservation, in their wordsThe fact from their own setup that answers it
Sep 9, Jay"we also use the leasing function for our renewals, as opposed to the renewals function"; "some of the reporting functionality that relies on pulling a renewal report […] isn't working". Also: "we'll get set up on that, all for it."Their Renewals screen already lists 29 rows for Oct 20–Jan 18 and the 11 recent offers were built there (S14). They are half switched; the switch is finishing the defaults.
Oct 7, Jay"I think right now, Clara building the templates is out of scope. I mean, the one form, the one page renewal could be in scope." Fede: "it sounds like you're not ready yet." Jay: "Yes. To start."11 of 11 recent offers use the one page (addendum "AF Renewal Function: RENEW (SIMPLE)") alone. The one page is the whole packet at every property except Northridge.
Oct 7, JayMarket rents: "The short answer is not really" current; "it displays on the rent roll". Entering them "is manual, I know Clara can do that for me".Fede already offered on the call: "send it to me and I'll do it for you." Still open; it is a write at the customer (their OK + your go).
Oct 7, Jay"maybe we rip the Band-Aid and we do a full renewal on all the people at 100 now, on new paper, and that updates them to 150, and then everybody gets standardized."Their idea, not ours. The $150 month-to-month fee is typed as a future-dated charge today; a re-papering run is exactly a batch of one-page packets.
Oct 7, Jay"if you look at Pomona I have set the default templates for a new lease. We don't have a default template for a renewal, but we could, I'm sure, get there pretty easily."True for Pomona; at Elm and Colorado the renewal pre-fill is wrong (12 addenda, an old pet addendum, an old amendment), at five properties it will pull 12–13 move-in addenda, and Northridge's renewal defaults point at the NEW LEASES template (S12).
Oct 14, Jay"the biggest obstacle in renewals right now is that our leasing templates are still an open item for us"; "we would have to see it first"; "too much other stuff going on for Jason and I to budget 2027 right now."The lease rewrite and the renewal amendment are separate; the amendment is done. Budget: Jason's rule is flat to lock things in; their sheet is mostly flat or +$25. Seeing it first = the parked offer.
Oct 20 (your retelling)"really what they want is for Clara to prepare the lease package, but then don't send it until they review it." "they already did it through almost February"; "we don't know what the price is, and we might want to give them 2 weeks free, so we're not ready." "it's 10 minutes of clicking, why can't Clara just do it for me?"That is the Prepare rung, in their words. Nothing goes out until December (for March): November is the setup clean-up, the test property and the proofs. A concession ("2 weeks free") is the special-provisions line, typed on 2 of 11 past offers.

Promises on the record: Sep 30 (Sean) "it'll never make a decision on its own"; Oct 7 (Sean) "for the first few flights, we'll just flag all of them for human review"; Oct 7 (Fede) the rent sheet load; Oct 14 (Fede) "when you guys are ready with templates, I can do that for you as well", a weekly pre-read before their Tuesday 11:30 meeting. The Oct 8 plan to email them "renewals live Monday at +$25" is not confirmed sent. Internal counts disagree (18 templates on Oct 7; 10 templates and 52–56 addenda on Oct 20); the Oct 20 inventory (12.5) is the number to use. Kat has no line of her own in any transcript; the Oct 20 meeting was not recorded. S15

The one layer that makes this scale (answer to "is there a concept I am missing?")

flowchart LR
  L["Lease facts\n(from the PMS: term, rent,\noriginal start, tenant, unit)"] --> R
  D["The decision\n(from the list: new rent,\nterm, special terms, hold)"] --> R
  P["Property packet default\n(set in AppFolio once:\nlease or addendum, attachments)"] --> R
  K["Field recipe, per template\n(data, not code: each typed field is\na fact, a decision, a standing answer,\nor an ask)"] --> R
  R["Clara builds the packet"] --> AF["AppFolio offer\n(parked or sent, by setting)"]
  classDef data fill:#f3f4f6,stroke:#6b7280,color:#111;
  classDef clara fill:#e8f1ff,stroke:#1d4ed8,color:#0b2a6b;
  class L,D,P,K data;
  class R,AF clara;
Why Camellia feels easy and Western Slope hard: Camellia's packet is one PDF form with no typed fields, so the engine only needs the lease facts and the decision. Western Slope's templates have typed fields (6 on the simple addendum, about 30 on Northridge), and the office overrides the property default at 2 of 8 properties. Nothing about that is customer code. The missing piece is one data layer, the field recipe: for every template a customer uses, each typed field points at a lease fact, a decision field, a standing answer (the same every time) or "ask the office". AppFolio returns the field list per template, Clara drafts the recipe from the customer's past offers, the office corrects it once. Ten customers with different templates are ten recipes, zero code. The packet documents come from AppFolio's own per-property default, which is why 12.5 matters: a clean default is a recipe with nothing to override. This is section 11.4 said once more in one picture; it is the same architecture, not a new one.

A case from their own records for tomorrow (raise it gently, no names): the Northridge lease Fede opened (occupancy 876) is a month-to-month tenant who asked for a 12-month lease; on Aug 2 the office promised one at the same rent from Aug 1; as of Oct 20 no offer was ever prepared, and the form now defaults the start to Nov 1. Their list for Oct 20–Jan 18 holds 29 rows (24 eligible, 10 of them month-to-month, 5 out for signing, none parked). This is the "promised, never built" case the packet step exists for. S14

Sources: the section 11 list (S1–S15). The Oct 20 team-meeting with Western Slope was not recorded; today's two recordings (the Situs leasing meeting 11:04 and the Gera sync 12:32) do not cover renewals.

13 · Update 2026-10-21: the document engine (new design, decided Oct 21)

Decided by Fede, Oct 21 The full page, with figures, the Oct 20 proof and the decision list: /a/document-engine-2026-10.

Oct 21 morning: Fede decided (design yes, Camellia inside the MVP on the one engine, AI reasoning as a skill for now, the four robot fixes go); building started.

14 · Update 2026-11-03: leak audit before Renewals goes back on at Western Slope

Flipped to Preview, 2026-11-03 20:04Z Fede's press: "1. preview". One write (change off-to-preview-f40885ce): Renewals switch off to on with the Preview mark; read back on, preview; buildings reading Preview 0 to 80 (10 not in PropFlow stay Off); Courtyard and Lincoln still Preview. 0 renewal holds since the flip (control: 133 since Nov 1). The first daily scan opens November's list as a Preview hold with no reviewer email. Undo: one restore command, file kept with the plan. Marker backfill: a separate press, not run.

"Too many gates, not one choke point?" Yes. Each of the 14 renewal doors asks the mode itself; a registry and a drift test keep them in line. The Oct 30 door was one that never asked. One send choke point is a separate design for Gera's lane.

Every door, by mode

Live is left out: it is not on the table for Western Slope, and at Live every door sends without a hold.

Door (where)PreviewSupervisedOct 29–30Verdict
Monthly list email to reviewers (open-batch.ts:59, held-reviewer-email.ts:141)Hold + our Slack card, no emailEmails Jay and Kat (the approval ask)Sent: the leakSafe both (#23805)
Offer text / offer email (send-renewal-letter-mms.ts:297, send-renewal-email.ts:323)Recorded onlyHeld, parked on the listNothingSafe both
Offer call (initiate-renewal-call.ts:104)RefusedRefusedNothingSafe both
Month-to-month warning (mtm-warning-send.ts:70)RecordedHeldNothingSafe both
Replies to tenants, incl. AppFolio inbox (renewal-reply-review.ts:76)RecordedHeldNothingSafe both
Inbound renewal calls (preview-call-door.ts:33)Off routeClara answers tenants live, no press (by design)NothingSafe under Preview; under Supervised a tenant hears Clara
Per-tenant manager page (renewal-notify.ts:332)NothingNothing (the list only)NothingSafe both; registry row still says "not wired" (stale)
Renewal notes and decision requests to the team (renewal-yes-office-notice.ts:230, decision-request-hold.ts:70)Held, approval only recordedHeld; reviewer email goesNothingSafe both
AppFolio fill / park (renewals-entitlement.ts:74, renewal-paperwork-packet.ts)Writes nothing; renewal pauses with its draft (#23433, #23880, #24218)Writes; but Western Slope's paperwork setting is "team", so nothing is parkedNothingSafe both at Western Slope
Holdover to month-to-monthNothingNeeds a per-building flag and an engineering armNothingSafe both
Daily scan, Temporal renewal-auto-start-daily 09:00ZOpens the list as a holdSame; the flip itself also runs one scan at once (admin/modules/route.ts:250)Opened the listSafe both

Dry run: what day 1 would produce

Read-only list build for Western Slope as of Nov 3 (writes blocked, send keys removed, no AppFolio calls): 15 leases on the November list, 10 with the policy offer and 5 held for a balance.

Day 1PreviewSupervised
List hold + Slack card in our channel11
List email (15 names and rents) to Jay and Kat01, at the moment of the flip
Tenant texts, emails or calls00 sent from the list (10 drafts parked); inbound renewal calls answered live
Held team notes emailed to Jay and Kat0Not dry-run: each renewal Clara starts can hold notes, and under Supervised their reviewer email goes
AppFolio writes00

Courtyard and Lincoln keep their own Preview rows, so their leases stay Preview whichever you choose.

The flip

No marker means Preview (Fede, Nov 3: "no marker means lower level")

Today an "on" module with no stored mode runs Live. Fix in three steps, because the reader treats an unknown marker as Off: (1) PR 1a, #24932 (backfill tool: #24959, dry run: 10 company + 10 building rows): "live" becomes a stored value and every Live pick stores it, no behavior change; (2) write an explicit "live" on everything Live today (your press); (3) PR 1b: no marker reads Preview.

CompanyLive today with no marker (would drop to Preview)
JP&CoLeasing, Renewals, Maintenance
Situs GroupLeasing
Western SlopeLeasing, plus 10 building rows (Ember Lane, Florida Street)
Test companies (Willows sandbox, Fairhaven, Demo)Willows: Leasing, Renewals, Maintenance · Fairhaven: Leasing · Demo: Leasing

Source: read-only pass over all 8 company rows and their 204 buildings through the production resolver, 2026-11-03. ConAm and PropFlow Staff are all Off; no company relies on the all-on default.

PropFlow Docs