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
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 | Today | Target, after slices 1 to 6 |
|---|---|---|
| Leases where PropFlow and their board disagree | 17 of 32 C12 | 0: the weekly pre-read becomes the board |
| What PropFlow knows went out | AppFolio offers only, and only while no Clara renewal is open C10 C57 | AppFolio offers, texts and emails, each dated |
| Renewal messages checked for a teammate's touch | None: the only check is Supervised review C35 C27 | Every one, in every mode |
| What an approval sends | Everything on the list, within seconds C53 C26 | Exactly what the confirmation listed |
| Rhythm | A monthly list C33 | The company's own day and time |
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.
| At each wake, before any scheduled message | Clara does | Harness 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 her | First case: Pomona Park 305, Bev's Oct 6 text |
| 2 · A contract is out or signed in AppFolio, or the tenant replied on any channel | Stop reminders; answer questions only | Colorado Ave unit B: yes on Sep 28, contract Oct 6 |
| 3 · Neither | Send the scheduled message | A December row with no staff text |
| A read failed or is stale | Do not send this wake; retry at the next; hand off after three | Planted: 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.
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).
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
| Piece | Today |
|---|---|
| Their renewal messages | Bev'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 them | Only 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 Slope | Off 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 renewal | Skips 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 message | Only 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's | Clara'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 message | Waits 24 hours, then expires: the reminders stop and the manager is paged. Only a message parked on an unapproved list waits longer C52 |
| Meeting notes | Forwarded notes are on at Western Slope; the video join is built and off C15; no invite has arrived C16 |
| Clara reading notes | Stored, never read: two writers, no reader C17 |
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
| Layer | What it does | Built today | New |
|---|---|---|---|
| ① Pre-read | The 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 C41 | A monthly list C33 | Weekly: 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 C42 | The reply reader C37; notes stored, never read C17; the note reader is a prototype C19 | The one engine (slice 5): Fede's go 2026-10-15, "build and battle test that layer" |
| ③ Confirmation | Same 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 C42 | No: today an approval sends at once C53 | Slice 2 |
| ④ Engine | Unchanged: 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 C55 | Built C36 | Nothing |
| ⑤ AppFolio door | Clara's messages go inside AppFolio, as staff's do | The 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 C23 | Tenant threads and a first text with no thread (AppFolio Communications lane); one door for everything later (slice 10) |
| "What was sent" reads | Know what already went out, by channel, before Clara sends | The AppFolio offer, while no Clara renewal is open C10 C57 | Slice 6, with the reads in the next figure C56 |
| Staff-touch rule | Before 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 C50 | No general check; planted case not yet verified C14 | A fix, no switch (slice 1) |
| Company brain | Private notes. Clara reads them only for staff-facing work (the confirmation, the terms), never inside a tenant message | The store; no reader C17 | One staff-only reader (slice 5) |
| Tenant history, later | Work 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 C50 | No | Later (slice 7) |
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"]
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"]
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"]
| Input to the engine | Where it comes from | When |
|---|---|---|
| Policy: rent rule, eligibility, who sends the paperwork | Company and building settings C40 C55 | Today |
| The team's decisions | Their reply or their meeting | Slices 2 and 5 |
| What already happened: offers, replies, teammate touches | AppFolio, through the sync, the mirror and the robot's reads | Slices 1 and 6 |
| Tenant history: work orders, complaints, payments | AppFolio, as fields on the picture; the tenant page already holds it C48 | Later |
| Market: vacancy, comparable rents, similar vacant units | Their own portfolio C42 | Later |
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
| Decision | Options | Recommendation | |
|---|---|---|---|
| D1 | One 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. |
| D2 | Closed 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. |
| D3 | Fede'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). |
| D4 | Collapsed (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). |
| D5 | Read 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. |
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
| # | Slice | Fix or new · switch | Rungs | Proof (the planted defect must go red) | Size | Unblocks |
|---|---|---|---|---|---|---|
| 1 | Fede 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 C51 | Fix · no switch | 1 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 | ~250 | Clara at Western Slope without talking over a teammate |
| 2 | Confirmation email after a reply, then after a meeting; one approval releases exactly what it lists C42 | Improvement to the list review · no switch | 1 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 | ~250 | The guard for both inputs |
| 3 | The 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 C34 | Fix · no switch | 1 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 step | Western Slope keeps its review after it moves to Live, planned from about 10/21 C40 |
| 4 | Weekly 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 C52 | New · Dark: renewal.weeklyReview | feature: the renewal pre-read and confirmation run weekly on the company's chosen day and time | proof: pending | turn-on: Fede | 1 2 3 5 6 | Fairhaven gets the pre-read at the set time, with last week's changes. Planted: a lease decided last week shows as new | two PRs, ~250 each | The Tuesday rhythm without us |
| 5 | One 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 C17 | New · Dark: renewal.meetingNotesDecisions | feature: Clara turns the team's meeting notes into renewal decisions for them to confirm | proof: pending | turn-on: Fede | 1 2 5 6 | Battle 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 | ~300 | The meeting input |
| 6 | Re-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 C46 | Fix · no switch | 1 2 4 | Willows: 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 land | The pre-read's "already sent" column; D1's safety net |
| In progress | The 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 C56 | Read-only robot change · no setting | probe | Verified 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 D5 | small | Chat rows in slice 6; emails wait on D5 |
| Later | 7 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 C43 | 7 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: Fede | 1 to 6 | Each with its own planted defect | ≤300 each | Fede'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
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 today | Code that needs a go or a decision first | Manual 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.
Every result shows its planted control going red; a check with no control does not count.
| Test | Cases | Result | Planted 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 subscription | real · (a) a unit named twice · (b), (b2) a contradiction · (c) a unit not on the list · (d), (d2) one global instruction | 21 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 C54 | G1 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 C19 | Controls test the grader too |
| Claim | Evidence | Row |
|---|---|---|
| Their renewal offers also go out as AppFolio texts | 2 of 8 December units carry a bulk offer text (Sep 28, Oct 6), in a read-only capture of their texting inbox | C6 |
| The robot's thread history is texts only | 1,871 messages and 433 list rows, 0 emails | C5 |
| Price email, AppFolio's offer and its reminders are all inside AppFolio | One tenant's Emails panel and its exports | C1 C2 C48 |
| Their leasing mailbox sees none of it | 1,832 messages, 0 renewal offer emails | C20 |
| PropFlow vs their board | 17 of 32 rows disagree; January emailed Oct 13, December Sep 1 | C12 C49 |
| An approval sends fast | Three Fairhaven list approvals sent the offer text 18 to 26 s later, one of them by email reply | C53 |
| The tenant sync is stale | 0 runs since Sep 9 | C18 |
| Not yet proven: the planted teammate-text case | Written for Fairhaven, not run | C14 |
| 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 seeded | C32 C13 |
| Disproven: an email row from the inbox list | Probe 2026-10-15: email flag ignored (byte-identical 20 rows), chat flag honored (19 texts + 1 chat), texts off gives an empty list | C58 |
| 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 route | Production probe after #532 merged: 20 rows for one tenant, 6 of them emails, typed by channel | C59 |
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.
| Step | Reply | What Clara did | Result |
|---|---|---|---|
| L01 | From a stranger | Refused it and alerted the team | PASS |
| L02 | Asks how to reply | Sent the how-to line | PASS |
| L03 | A question | Answered the question | PASS |
| L04 | Unit 305 rent to 2,645 | Recorded it | PASS |
| L05 | Corrects unit 305 | Read "Actually" as a name; no correction | FAIL |
| L06 | Concession for unit 101 | Recorded it | PASS |
| L07 | Six-month term for unit 4 | Recorded it | PASS |
| L08 | Month to month for unit 1254 | Recorded it directly, no question needed | PASS (better than expected) |
| L09 | Ambiguous lease | Asked which lease, but listed struck unit 2 | PASS, with defect |
| L10 | Do not contact unit 13 | Recorded the skip, kept the row | PASS (better than expected) |
| L11 | Unit 1460-1, not on the list | Mapped it to unit 1460-4 | FAIL (nothing sent) |
| L12 | Misspelled tenant | Said it could not find them | PASS |
| L13 | Conflict on unit 1460-4 | Asked about it | PASS |
| L14 | "Approve, send the rest" | Approved the list; no tenant message went out | FAIL |
| # | Defect | Fix PR (all six merged on main 2026-10-16, no switch, live everywhere) |
|---|---|---|
| 1 | An 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 |
| 2 | The 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 |
| 3 | A correction ("Actually…") is read as a tenant name. | #20377 |
| 4 | A unit not on the list is matched to the nearest one. | #20369 (merged) |
| 5 | The "which lease?" question offers a struck row. | #20390 |
| 6 | Any reply Clara did not act on is stored as an open question with no lease. | #20396 |
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.
| Meeting | Units | Match | Partial | Miss | Asked back | Ambiguous |
|---|---|---|---|---|---|---|
| Jul 16 | 10 | 5 | 0 | 0 | 0 | 5 |
| Aug 6 | 18 | 7 | 0 | 1 | 3 | 7 |
| Aug 13 | 18 | 11 | 0 | 0 | 1 | 6 |
| Aug 20 | 16 | 6 | 0 | 0 | 2 | 8 |
| Sep 17 | 6 | 3 | 0 | 0 | 1 | 2 |
| Oct 15 | 21 | 7 | 0 | 0 | 1 | 13 |
| All | 89 | 39 | 0 | 1 | 8 | 41 |
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 lost | How often | Example | Kind |
|---|---|---|---|
| Transcriber splits unit numbers ("3 11", "6-14"), the right row is rejected | 3 rows, all asked back | Camellia 311 | bug |
| Unit named on one line, decision on the next | 5 rows, all asked back | Camellia 515: "515?" then "she left without saying anything" | bug |
| A quote that spans two lines is dropped | 1 row | Camellia 204: sent to the lawyers, don't offer | bug |
| Same meeting, different answer per run | 2 of 6 meetings | Camellia 518 vacating in 1 of 3 runs | bug |
| "They're gonna renew": no decision exists | 12 rows, engine does nothing | Camellia 402 | policy |
| Paper lease: no decision exists | 10 rows, asked, held or nothing | Camellia 106 | policy + design |
| Unit not on the list that day | 12 rows, reported correctly | Camellia 415 | data |
Decisions for Fede
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).
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).
| Lease-end month (list sent) | Rows | Match | Partial | Miss | Asked back | Ambiguous |
|---|---|---|---|---|---|---|
| November 2026 (Aug 11) | 11 | 1 / 1 | 0 / 0 | 2 / 0.3 | 4 / 5.7 | 4 / 4 |
| December 2026 (Sep 1) | 13 | 1 / 1 | 0 / 0 | 0 / 0 | 8 / 8 | 4 / 4 |
| January 2027 (Oct 13) | 12 | 0 / 10 | 0 / 0 | 0 / 0 | 11 / 1 | 1 / 1 |
| All | 36 | 2 / 12 | 0 / 0 | 2 / 0.3 | 23 / 14.7 | 9 / 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 lost | How often | Example | Kind |
|---|---|---|---|
| A house named by its street address cannot be pointed at | 6 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 froze | a Morningside house with a ½ in its number, confused with Hill Avenue 2 | bug |
| A teammate's name read as a resident | 3 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 reply | 24 of 36 replies recorded nothing | January: engine decided 7 of 10 rows, nothing recorded | policy |
| "The resident says he is renewing" sends the offer again | 2 rows: sent 6 of 6 as written, 1 of 6 with names | Colorado Avenue B | policy |
| "Accepts the promo", promo not on the list | 1 row, asked 6 of 6 | Morningside house: Clara asks what the promo was (right) | data |
| A "?" in a reviewer line refuses the whole reply | 2 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
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).
| # | Question | Who answers | Row |
|---|---|---|---|
| 1 | Does 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 panel | C2 C40 |
| 2 | Clara's first touch at Western Slope: a text, as the engine does today, or an email like Bev's? | Their team, at Tuesday's meeting | C1 C36 |
| 3 | Between a tenant's yes and the AppFolio offer: who builds it, how long it takes, and when the lease templates are ready | Kat and Jay | C41 C40 |
| 4 | Where 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 team | C49 C18 |
| 5 | Where do the prices come from: the unit pricing matrix from their budget, which Kat works from? | Kat | C41 |
| 6 | Does an invite to hello@ reach Clara, or should Jason use the shared Clara address? | Engineering | C47 C41 |
For engineers. File names, line numbers and PR numbers appear only in this section.
| Slice | Seam | Code | Notes |
|---|---|---|---|
| 1 · staff-touch check | The per-send review step every renewal message already passes, ahead of the Supervised check | renewal activities 947–952, 1477–1482, 1910–1915, 2246; text review 88–94; email review 68–76; read-person-picture.ts | The 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 · confirmation | The reply reader: a reply produces the confirmation instead of the approval; approving the confirmation applies the edits and approves the list | batch-reply.ts:1–33, 414; the list's renderer; the coworker email door | The 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 setting | The list gate in the daily scan, plus the per-send step's list check when a company is Live with the setting on | scan-batch.ts:85–89, 136–140; review-offers-before-sending.ts:12–21; keys.ts:1391–1398 | A data step first writes "off" for every company on Live today, so their behavior is unchanged C34 C40 |
| 4 · weekly | The scan's month key becomes a company-week key; the time comes from the new company setting | scan-batch.ts:2, 7–11, 123–125 | If the workflow's park path changes, it carries a patch marker and climbs rung 4 (workflow histories; renumbered 10-17) C33 C52 |
| 5 · note reader | Email notes intake and meeting notes into the company brain; one staff-only reader | staff-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 sent | The sync's renewal writer, the mirror's rows, the robot's inbox list read | pms/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 |
| Rule | Slices 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 | ||
| Budget | Every 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 | ||
| Pages | No slice adds a per-tenant page or email to staff. In Supervised, held messages show on the pre-read and the list only | ||
| With | What | How this page handles it |
|---|---|---|
| Gera's portfolio model: the org is the wall | Where 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 C41 | Today: 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 lane | The 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 C44 | Assumes 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 lane | The 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 C50 | Reuses 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 page | D1 (b): an approved list sends at once C40 | Superseded 2026-10-15 by the confirmation, for both inputs C42 |
| Fede, 10/09: one list on the 1st, no setting for it | The monthly rhythm C40 | Superseded 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) |
| Item | What happens | Row |
|---|---|---|
| The flip | Renewals off to Supervised opens the first list that minute; the next list comes a month later, until slice 4 | C40 C33 C34 |
| Reviewers | The 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 verified | C40 |
| Mid-month leases | A lease that opens after the list went out gets a 24-hour hold, which expires, stops the reminders and pages the manager, until slice 4 | C40 C52 |
| Paperwork | Unset 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 answer | C55 C39 C36 |
| Texts | From Clara's own line, as the 10/12 plan had them; the AppFolio text switch would hold every renewal text until tenant threads are mirrored | C38 C40 C44 |
| January | All 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 reply | C49 C45 C37 |
| Notes | Forwarded notes are matched to the company by the sender's domain and stored; nothing reads them until slice 5 | C15 C47 C17 |
| The invite | The 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-month | Fede'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 verified | C43 C40 |
| Approval | Until slice 2, approving the list sends the offers at once, within seconds | C53 C40 |
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.
| # | Claim | Status | Proof |
|---|---|---|---|
| C1 | Bev's renewal price email goes out through AppFolio from the shared Assistant PM login, with Opened and Delivered status | VERIFIED | Fede's screenshot of one tenant's Emails panel; the emails export (Aug 11 "Upcoming Lease Renewal", from the Assistant PM login) |
| C2 | AppFolio emails the tenant "Review your renewal offer" when the office creates a Renewals-module offer, then reminders on day 1, 2 and 7 | VERIFIED | Emails export: Oct 6 offer; reminders Oct 7, 8, 13, from AppFolio's no-reply address |
| C3 | Tenant email replies come back into AppFolio, both ways | VERIFIED | Emails export: a "Re: Renewal" thread, Nov 2025, from the tenant and through AppFolio's mailer for the company |
| C4 | AppFolio's Inbox shows emails and texts in one thread timeline | VERIFIED | Fede's screenshot, 08:42 MT |
| C5 | The thread history our robot fetches is texts only; email cards are not in it | VERIFIED | AppFolio 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 |
| C6 | Their renewal offers reach tenants as AppFolio bulk texts on Sep 28 and Oct 6; 2 of 8 December units have one | VERIFIED (texts) | Raw capture and live read, 2026-10-15 (pms-mirror-harness out/ws-renewals-2026-10-15) |
| C7 | The inbox mirror is on only at Willows, off at Western Slope and Situs; leasing only; tenant threads held | VERIFIED 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 C65 | AppFolio Communications session, 2026-10-15 |
| C8 | Western Slope's renewals module is off; prospects and maintenance only | VERIFIED | Production read 2026-10-15, enabled modules |
| C9 | 32 Western Slope leases end November 2026 to February 2027 | VERIFIED | Production read 2026-10-15 |
| C10 | AppFolio'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" dot | VERIFIED (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 |
| C11 | No API report or robot route reads a tenant's Emails panel or Communications | VERIFIED (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 |
| C12 | Their Monday board: 17 of 32 rows disagree with PropFlow; January emailed Oct 13; December emailed Sep 1 | VERIFIED | Monday export parsed (ws-arch-scripts/parsed.json); 13-monday-board-analysis.md |
| C13 | One renewal workflow per lease; approval releases parked first messages; no weekly or per-company schedule; "check before send" never built | PARTIAL: release by approval not yet verified | File 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 |
| C14 | Renewals have no "a teammate already reached out" check; only a human-replied flag on the text and letter, set by a manager's email reply | PARTIAL: code verified, planted case not run | File 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 |
| C15 | The 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 |
| C16 | No invite from Western Slope has reached Clara; no Monday guest invite | VERIFIED | Production read of 501 inbound email records since Oct 13 |
| C17 | The company brain store exists; Clara never reads notes when answering | VERIFIED | File 19, row 17: the lint allowlist has 2 files, both only save notes; no app-code reader |
| C18 | Tenant sync: 0 runs since Sep 9 | VERIFIED | Production run log (issue #20009) |
| C19 | Prototype: meeting transcript to per-lease decisions, every row right, 3 runs on each of 7 cases, 0 invented quotes, controls red | VERIFIED | poc-notes-to-decisions/runs and grade.py, re-runnable |
| C20 | Their leasing mailbox: 1,832 messages ingested, 0 renewal offer emails | VERIFIED | Production read 2026-10-15 (ws-renewal-state/ingest.json) |
| C22 | Jay's "has opened e-mail" tracking is AppFolio's email tracking | VERIFIED by C1 and C2 | Emails panel screenshot (Opened status) |
| C23 | Nothing in PropFlow reads or sends the email side of the AppFolio inbox | VERIFIED by the AppFolio Communications session; all-channels read approved 2026-10-15, result pending | Scoped 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) |
| C24 | The 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 pending | Robot 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 |
| C25 | The board's "Offer sent" dot is filled from the renewal's open time when no letter time exists | VERIFIED | map-renewal.ts:763–764; board-shared.ts:234 |
| C26 | Under an approved list, a day-0 offer text gets a per-send hold made and approved in under 1 second | VERIFIED | File 19, row 13 (c), 3 Fairhaven holds |
| C27 | No production property has its delivery mode set to AppFolio (0 of 159), so the human-replied flag is written nowhere today | VERIFIED | File 19, row 14 (c); verify/r14.out.json |
| C28 | Meeting join: 30-minute late limit, joins 1 minute early, 900-second call cap | VERIFIED | meeting-invite-intake.ts:49, 170; meeting-invite-workflow.ts:38, 40, 106; call-binding.ts:47–51 |
| C29 | The renewal email path never reads the human-replied flag | VERIFIED | File 19, row 14 (a) |
| C30 | Reminder waits default to 24 hours and 7 days; comments saying 48 hours and 5 days are stale | VERIFIED | File 19, row 13 (a) |
| C31 | The robot's guest-card messages read carries an email channel, for prospects only | VERIFIED | File 19, row 11 |
| C32 | All 6 Fairhaven holds ever parked on a renewal list were rejected; none was released by approval | VERIFIED | File 19, row 13 (c); verify/r13.out.json |
| C33 | The list opens once a month in the daily scan; there is no weekly or per-company schedule | VERIFIED | scan-batch.ts:2, 7–11, 123–125; schedules in file 19, row 13 |
| C34 | The list opens only when the building is Supervised and "Review offers before sending" is on; unset means on; a header comment is stale | VERIFIED | scan-batch.ts:85–89, 136–140; review-offers-before-sending.ts:12–19, 21; keys.ts:1391–1398 |
| C35 | Every 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 stage | VERIFIED | Renewal 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 |
| C36 | One 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 stop | VERIFIED | client.ts:158; renewal-email-review.ts:4–5; renewal workflow 3900, 3922–3926, 3928–3937, 3103–3108 |
| C37 | The reply reader for the list exists: approve, change or skip by email reply | VERIFIED | batch-reply.ts:1–33, 414 |
| C38 | The 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 13 | VERIFIED | dispatcher.ts:494–499; text-door-address.ts:1–6, 57; AppFolio Communications session (Oct 13 send) |
| C39 | The renewal letter goes by picture message from our own line | VERIFIED | send-renewal-letter-mms.ts:16–23, 331 |
| C40 | The 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 1st | VERIFIED | renewals-levels-of-autonomy-2026-10 extract, lines 54, 56, 58, 72, 101, 108, 155, 157, 173, 201, 245, 353, 355, 506, 632, 1580, 1588 |
| C41 | The 10/14 weekly sync with their team, quoted from the raw per-speaker transcript; lines labeled "J." are attributed to their team | VERIFIED | #transcripts thread, lines 310, 1069, 1073, 1099, 1132, 1144, 1146, 1200, 1237, 1264, 1277, 1291, 1298 |
| C42 | Fede'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 approval | VERIFIED | File 15, lines 33–45, 48–60, 62–88 |
| C43 | Fede'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/20 | VERIFIED (dictation record, matched by transcript lines 1073, 1237, 1277) | File 00, items 3, 4, 4d, 5, 10 |
| C44 | AppFolio 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 pending | VERIFIED by the owner lane | File 07 notes; their page's 8c and 8d headings; file-message.ts:8, 167 |
| C45 | The start check skips a lease only when an offer is already prepared or open in AppFolio | VERIFIED | renewal-classify.ts:145–148, 277–283 |
| C46 | The 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-in | VERIFIED | read-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 |
| C47 | Where 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/14 | VERIFIED | company-brain-design extract lines 78, 133, 393; staff-meeting-notes.ts:12–16; portfolio-architecture extract line 4960; transcript line 1146 |
| C48 | One 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 history | VERIFIED | Emails and texts exports, dates only; files 16 and 17 |
| C49 | January: 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 record | VERIFIED | ws-arch-scripts/parsed.json; ws-renewal-state/board-rows.json (08:08) |
| C50 | Lead 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 setting | VERIFIED as that lane's statement | File 09 notes; the lead-source-gate page |
| C51 | Only the sync talks to AppFolio, once per client; the mirror's ceiling is 4,000 requests a day, about 10 per thread | VERIFIED (per-thread figure is an estimate) | prospect-conversion.test.ts:278; watch.ts:107; file 12 |
| C52 | A 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" | VERIFIED | Renewal workflow 2441–2470, 2477–2482, 4159–4185; held-message-max-age.ts:17 |
| C53 | Three Fairhaven list approvals sent the offer text 18 to 26 seconds later, two on the page and one by email reply | VERIFIED | File 19, row 13 (c); SMc168c9…, SM3995707…, SM282ef1… |
| C54 | The prototype re-run on 2026-10-15 and the added G6 control | VERIFIED | grade.py; poc-g6/make_g6.py and its case file |
| C55 | Who sends the paperwork: unset means their team; with their team there is no letter | VERIFIED | keys.ts:1374–1385; renewal workflow 3727–3729 |
| C56 | The 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 seen | VERIFIED by the AppFolio Communications session | Decision log 2026-10-15 16:00Z; appfolio-browser-agent PR #530 |
| C57 | While Clara's renewal is open, the sync drops a new AppFolio offer and logs "manual cancel needed" | VERIFIED | pms/writers/renewal.ts:532–551 |
| C58 | Inbox 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 only | VERIFIED (AppFolio Communications session) | ~/agents/pms-mirror-harness/out/inbox-email-probe-2026-10-15/ |
| C59 | Per-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 boundary | VERIFIED (AppFolio Communications session, production, read-only) | harness out dir (raw capture with PII, not copied) |
| C60 | Fede'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" | VERIFIED | Session 002 transcript, 2026-10-19 afternoon (dictated) |
| C61 | Western 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 us | VERIFIED (production, read-only, 2026-10-19) | door/renewals/ws-renewals-today.md §A, §F; raw: work/ws_dynamo.json, work/ws_email_ingest.json |
| C62 | 34 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 13 | VERIFIED (production, read-only, 2026-10-19) | ws-renewals-today.md §B, §C; work/live_leases.json |
| C63 | The 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 phone | VERIFIED (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 |
| C64 | Supervised 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 one | VERIFIED (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 |
| C65 | Tenant 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 unset | VERIFIED (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 |
| C66 | The 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 resolver | VERIFIED (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 |
| C67 | POC 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 kind | VERIFIED (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) |
| C68 | AppFolio 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 page | VERIFIED (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 |
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
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
| Leg | Can Clara send it as the team today? | Call |
|---|---|---|
| Text in the tenant's AppFolio thread | Not 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 C63 | The channel for this launch |
| Email from AppFolio | No. Nothing in PropFlow or the robot sends AppFolio email; the inbox list endpoint does not even serve it C23 C58 | Deferred; not a this-week build |
| Email from leasing@westernslopepm.com | Yes (connected, we see its sent mail), but no renewal has ever left it, so it would not look like the team C61 C20 | Off; keep as today (no-phone tenants only) |
| The AppFolio offer and e-sign | Stays with the office (Fede, 2026-10-15) C43 C55 | Decided, unchanged |
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;
| Piece | Built | Hole | Fix size |
|---|---|---|---|
| Meeting notes → decisions | Engine 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 C66 | Nothing routes the notes to the list; today a human pastes them as a reply to the list email | hours; optional for week 1 |
| Hold each offer for Fede | Supervised holds every renewal text, reminder, letter and email on the approval queue | Approving 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) C64 | hours |
| Send through AppFolio | The 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 C68 | The 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 C38 | renewals-only door: hours (the dispatch already carries kind and module); tenant thread start: days, robot repo |
| Tenant reply reaches PropFlow | Clara's own door text is filed even on a tenant thread | Tenant 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 C65 | hours to a day |
| Clara answers only where she should | The 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 her | No "her last text was a renewal" guard, and the woken reply is labelled as a prospect's | in the same PR as the row above |
| Fede approves each reply | Supervised holds Clara's text and email replies on renewal threads; the woken reply re-enters the same path | Three 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 office | hours (words); a day (actions) |
| Message or action to a tenant or the office | Waits for Fede today (Renewals Supervised at WS) | After the minimum build |
|---|---|---|
| Day-0 offer text, after the team approves the list | no released by the list approval | yes build 2 |
| Reminder texts (day 2, day 9) | no same release | yes build 2 |
| Offer email to a tenant with no phone | no same release | yes build 2 |
| Clara's reply to a tenant on a renewal thread | yes except an urgent maintenance reply | yes; the urgent carve-out closes with decision D10 |
| Clara's reply to a tenant on any other AppFolio thread | n/a tenant threads never wake her | n/a the wake stays limited to threads where her last text was a renewal |
| Marking renewed, stopping reminders, the "tenant countered" note to the office | no the tools act when the reply is drafted | D10: words only (today) or actions too (a day of work) |
| Phone call to a tenant | yes Supervised default "calls go to the team" means no call | unchanged |
| AppFolio offer or application link made by the robot | n/a the office sends the paperwork; no Supervised check exists on these two robot writes | unchanged; 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 Slope | n/a Leasing is its own module | D7 decides whether the door moves them too |
| # | PR | Switch? | Size | Proof rung |
|---|---|---|---|---|
| 1 | Door 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 thread | the existing company setting gains a scope; dark until Fede flips WS | hours | unit + Willows |
| 2 | Supervised 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 release | none (fix to live behavior) | hours | unit + Fairhaven list |
| 3 | List rows show "no AppFolio text thread, will not send": read the mirror for each tenant's phone at list time | none | hours | unit + WS list dry run |
| 4 | File 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 tenant | none; lifts the tenants_later hold under the existing mirror setting | hours to a day | unit + Willows tenant |
| 5 | Reminders skip a tenant a teammate already texted (Fede's rule 1), read from the filed thread at each reminder wake | none | hours | unit + replay |
| 6 | Willows 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 day | Willows |
| 7 | Tenant 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 reach | none | (a) hours plus one live capture; (b) about a day, robot repo | Willows |
| 8 | Meeting notes to the list (notes intake or transcript for a company with an open list runs the reply reader) | none | hours | Oct 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).
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
| Question | Western Slope | Willows |
|---|---|---|
| Tenant messages held today | 707 on 245 threads; all would file onto 240 known people, none orphaned; 219 join 27 existing conversations, 488 open new ones, none a renewal conversation | 2 tenant-shaped threads |
| Rows that would wake Clara, today's rule with the hold lifted | 0 (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 blocks | 0 |
| Rows that would wake Clara, with the renewal guard | 0 | 0 |
| Renewal-window people with a thread | 20 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 none | the usual tenant test number has no inbox thread; a new one is needed for the live try |
| Risks the replay exposed | 193 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.
| # | Decision | Options | Recommendation |
|---|---|---|---|
| D7 | Decided (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 |
| D8 | Decided (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 |
| D9 | Decided (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" |
| D10 | Decided (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):
| Build | PR | What changes | Switch? | State |
|---|---|---|---|---|
| 2 | #21210 | At 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 unchanged | none (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 | #21216 | List rows mark a tenant whose phone has no texting thread in the PMS inbox copy ("will not send through the PMS inbox"); nothing else changes | none | reviewer 🟢; parked for the next batch train |
| 4 | #21221 | Tenant 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 history | none; lifts the hold under the existing mirror setting | reviewer 🔴 only on an older test that still pinned the hold; fixed; follow-ups #21274 #21275 #21276 |
| 7a + 7b (robot) | robot #580 | The 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) | none | merged and live in production (Oct 19, 7:3x PM MT) |
| 7b (app) | #21249 | A 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 exists | none; improvement to the dark door | reviewer 🟡; 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 | #21257 | While 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 unchanged | none (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 |
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.
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/`).
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.
| Step | Result | What happened |
|---|---|---|
| 2 · Transcript → decisions | PASS | EVAL-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 opens | PASS | October'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, approve | Approve 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 card | PASS (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 door | PASS | Approved 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 · Restore | PASS | Building 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:
Defects found Oct 21 (r5):
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.
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
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;
| Their packet, per property | What the office actually sends | The property's default in AppFolio |
|---|---|---|
| Situs-owned properties (single-family and small multi-family), Pomona Park, Courtyard | one 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 +$150 | the same |
| Two other properties | the same one addendum | differs: 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 |
| Northridge | a whole new lease ("Northridge NEW LEASES" template, 11 addenda, 4 attachments); 10 tenants month-to-month today | a 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
| Cause | What happened | Evidence |
|---|---|---|
| 1. The packet was cut on a premise the data does not support | Oct 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 shape | Camellia 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 ran | JP&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. Process | Five 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
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;
| Gate today (section 10) | On the paper leg | Why |
|---|---|---|
| Renewals module Off / Supervised / Live | replaced by one new value on the existing "who sends the paperwork" setting: Clara prepares, office sends; default off; Fede turns it on | a new customer-facing capability: setting, default off (rollout rule) |
| Eligibility rules (balance, late payments) | facts shown on the list, not a gate | the meeting decides; "renew at zero balance" is their rule |
| Monthly list-approval click (Jay or Kat) | delete for paper | the 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 leg | no tenant message exists until Send |
| Fede's hold on each offer | delete for paper | the parked packet plus their Send is the hold; Fede is not Western Slope's reviewer |
| Text-door shape check | not on this leg | no 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
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
| Part | Rule | Western Slope | Camellia |
|---|---|---|---|
| Which documents | the 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 amendment | the 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 v1 | one PDF form plus the letter, as the robot does today |
| Each blank | a 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 type | today'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 11 | no blanks |
| Options and deadline | from the decision and the company's standing answer | one 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 send | the "who sends the paperwork" setting | Clara prepares, office sends | Clara prepares and sends |
| Learning | no 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 |
The paper leg. Labels: proven at the Willows / built, unproven / missing.
| Piece | State | Evidence |
|---|---|---|
| AppFolio's park state with a Send button | proven at the Willows, by hand | Oct 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, script | robot scripts prepare-only and retry-prepared S4 |
| Prepare, Western Slope's method (addendum templates) | built dark Sep 28, unproven | robot #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 method | missing | the path always sends after preparing; only a no-write dry run exists S4 |
| Fill the six blanks | shape confirmed read-only Oct 20; a fill with values still unproven | their 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 → robot | missing | the app's input to the robot has no field for it; the mapper accepts one S4 |
| Start and deadline rules | wrong for them | robot: 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 ruling | the 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 deltas | the 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 choice | built on property defaults | wrong at 2 of 8 sampled properties; cannot do Northridge S4 S9 |
| "Prepared" read back onto the list | mapped, not fed | the 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 office | missing, small |
The texts leg, per session 002 at 21:00Z Oct 20 (its PROVEN / UNVERIFIED labels kept). Not needed for v1.
| Leg | State | Proof |
|---|---|---|
| Text in the tenant's existing AppFolio thread | merged | PROVEN 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 thread | merged Oct 20 | robot: 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 recorded | merged | PROVEN 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 AppFolio | not built | tenant email leaves Clara's own mailbox, not AppFolio S5 |
| Office emails after a yes or no (overnight step 8) | fixed, unproven | section 10, morning verdict; #21505 and #21507 live 21:43Z; rerun needs Fede at Slack to approve three test cards S5 |
| # | Piece | Switch? | Size |
|---|---|---|---|
| 1 | App: 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 off | a day |
| 2 | Robot: 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 rebuilds | none | two days |
| 3 | App: 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" note | none | two 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.
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.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.
Only D13 (the test property in their AppFolio, asked for tomorrow) blocks the proof; nothing blocks the build. The rest confirm what is recommended.
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:
s3://propflow-training-data/renewals-corpus/western-slope/2026-10-20/, Fede's yes Oct 20, tenant details inside, never public; 19 report row-queries were AppFolio's own read POSTs, nothing changed): status tabs, Renewal Summary (Oct–Dec starts), 11 document previews, 9 occupancies across 8 properties with their lease settings.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
| Who simplifies what | In AppFolio setup (we set it up, with your OK) | In the team's process | Clara takes over |
|---|---|---|---|
| The packet | Each 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 yes | Response 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 tracking | Nothing 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 signing | AppFolio 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
| Tier | Properties | What AppFolio pre-fills when you click Prepare Renewal Offer | What the office actually sends | What has to happen first |
|---|---|---|---|---|
| 1 · start here | The scattered single-family homes (7 sampled), Pomona Park | the one renewal page (6 typed fields); one Pomona tenant pre-fills 12 addenda carried over from their original lease | the one renewal page | nothing in AppFolio; Clara builds from the list |
| 2 · after a five-minute setup fix | 239 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 attachments | the 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 · later | Northridge; 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 up | Northridge: 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
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.
| What we'd change | Why it helps you | Who does it | Time 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 it | About 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 it | About 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 decide | About 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. | Together | About 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 it | About 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 it | About 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 it | About 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 decide | About 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 it | About 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 decide | About 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. | Together | About 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. | Together | About 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. | Together | About 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 decide | About 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 decide | About 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 decide | About 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. | Together | About 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
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.
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
| We do | You do | When |
|---|---|---|
| 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 |
| You said | What 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
| Date | Reservation, in their words | The 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, Jay | Market 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
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;
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.
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.
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.
Live is left out: it is not on the table for Western Slope, and at Live every door sends without a hold.
| Door (where) | Preview | Supervised | Oct 29–30 | Verdict |
|---|---|---|---|---|
| Monthly list email to reviewers (open-batch.ts:59, held-reviewer-email.ts:141) | Hold + our Slack card, no email | Emails Jay and Kat (the approval ask) | Sent: the leak | Safe both (#23805) |
| Offer text / offer email (send-renewal-letter-mms.ts:297, send-renewal-email.ts:323) | Recorded only | Held, parked on the list | Nothing | Safe both |
| Offer call (initiate-renewal-call.ts:104) | Refused | Refused | Nothing | Safe both |
| Month-to-month warning (mtm-warning-send.ts:70) | Recorded | Held | Nothing | Safe both |
| Replies to tenants, incl. AppFolio inbox (renewal-reply-review.ts:76) | Recorded | Held | Nothing | Safe both |
| Inbound renewal calls (preview-call-door.ts:33) | Off route | Clara answers tenants live, no press (by design) | Nothing | Safe under Preview; under Supervised a tenant hears Clara |
| Per-tenant manager page (renewal-notify.ts:332) | Nothing | Nothing (the list only) | Nothing | Safe 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 recorded | Held; reviewer email goes | Nothing | Safe 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 parked | Nothing | Safe both at Western Slope |
| Holdover to month-to-month | Nothing | Needs a per-building flag and an engineering arm | Nothing | Safe both |
| Daily scan, Temporal renewal-auto-start-daily 09:00Z | Opens the list as a hold | Same; the flip itself also runs one scan at once (admin/modules/route.ts:250) | Opened the list | Safe both |
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 1 | Preview | Supervised |
|---|---|---|
| List hold + Slack card in our channel | 1 | 1 |
| List email (15 names and rents) to Jay and Kat | 0 | 1, at the moment of the flip |
| Tenant texts, emails or calls | 0 | 0 sent from the list (10 drafts parked); inbound renewal calls answered live |
| Held team notes emailed to Jay and Kat | 0 | Not dry-run: each renewal Clara starts can hold notes, and under Supervised their reviewer email goes |
| AppFolio writes | 0 | 0 |
Courtyard and Lincoln keep their own Preview rows, so their leases stay Preview whichever you choose.
PUT /api/admin/modules {organizationId, module: "leasing.renewals", mode: "preview"} → setOrgEnabledModules sets the switch and the marker together. Same write with a read-back and a restore file: scripts/modules/off-to-preview.ts --only-org <Western Slope> --modules leasing.renewals (dry run, then --apply --confirm-table=propflow-prod). Rollback: the same call with mode: "off", and reject any list hold it opened.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.
| Company | Live today with no marker (would drop to Preview) |
|---|---|
| JP&Co | Leasing, Renewals, Maintenance |
| Situs Group | Leasing |
| Western Slope | Leasing, 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