Clara Onboarding — Overnight Fleet

The onboarding we ran at Situs Group on the night of Sep 1, turned into a repeatable 11-stage playbook, a data inventory with load/don't-load verdicts, and a review UX — plus nine decisions that need Fede.

Proposed — pending Fede's review · 2026-09-02

Contents

1 · The pitch, and what last night proved

You add Clara to your PMS. We deploy a fleet of agents overnight on your operations and come back the next day — sometimes in a few hours — with all the context. You spend a short session confirming, denying, and cleaning up what we're not confident in or found conflicts on. That's the onboarding.

This is the vision's "judgment with boundaries" loop run once, up front: outside policy Clara asks, the answer becomes policy, and she never asks again. Onboarding is that loop compressed into one night of collection and one short review session — instead of six months of the operator catching mistakes one at a time.

Commercially: pre-seed, seed raise in 6–9 months, pre-PMF, Situs is the first paid design partner. The overnight fleet is the wedge (nobody else can stand up a property's rulebook from the client's own records in one night) and it is the seed story (every property onboarded makes the next one cheaper).

What last night proved — one run, Situs Group, situsgroup.appfolio.com

Wall clockAgent-hoursEffort splitRe-pull once the toolkit existedOutputs
5 h 39 min
18:45 → 00:24 MT
24.4
~32 agent launches
45% load-bearing
38% supporting
17% noise
1 h 35 min
5,179 files / 142 MB, 1 orchestrator, 4 processes — call it a 1.5 h job
Property facts · 23 stable rules · 27 conflict rows (12 topics) · missing-facts list (14 clusters / 690 blocked rows) · human baseline to beat · 2,118-turn replay graded · go-live blocker list

Human baseline measured from their own records: median 46 min to an individual human answer in hours, 11 h after hours, 22% never answered. Replay: 56% of Clara's draft replies acceptable cold, before any of this context was loaded.

2 · Playbook v1 — 12 stages

~4.5 h of stage time; ~2.5 h wall clock with exports and entity pulls parallel and policy mining, replay and the config audit concurrent. PMS-specific stages change mechanics per PMS; PMS-agnostic stages survive a swap to Yardi or RealPage unchanged in shape.

Order changed on Sep 2 (D9). S5 documents and S7 policy mining were the lane we built first; both were then measured and neither moved the replay headline. The new stage S9b makes the question-bank coverage check an explicit gate rather than a report, and the post-run fill order puts live integrations ahead of documents — the calendar, availability, balances and application status first, because 64% of real question volume needs live state that no document can supply.

StagePMS-specific?InputsOutputsTimeAgents / modelGuard for the failure we saw
S1 Access, single login, write guardContract specific, shape agnosticPMS subdomain; Keychain credentials; a 2FA channel we control; written read-only authorizationShared cookie jar, session PID file, write-guard log, login-event log10 min1 session holder (never more), deterministic scriptFix #1. One session holder, N jar consumers. PID file, not pkill patterns — a missed pattern re-authenticated on a credential shared with the production JP runner. Hard cap of 1 login per run. Mandatory write guard with a pre-set allowlist for AppFolio's own report render and the calendar read-query
S2 Parallelism calibration + soakAgnosticLive jarProbed tab ceiling every walker reads10 min1, deterministicMeasured ceiling: 8 tabs / 8 concurrent fetches, 33 pages/min sustained. Never re-request an identical URL (that is what drew the one 429). Treat 429/503 as throttled-but-alive, only a redirect to login as dead — mistaking one for the other triggers the re-login hazard
S3 Report / bulk exportsSpecificJar; report list; the window~40 CSVs, named by their filter25 min1, deterministic + a standing retry passNever use a report as a volume denominator — a date-scoped work-order report returned 289 rows where the per-record walk found 3,810. Three reports never export in this account; move them to a known-unavailable list instead of retrying 113 times
S4 Entity pull, in dependency orderSpecificS3 CSVs as the indexOccupancies → tenants + full message history → work orders → guest cards → applications → renewals → calendar → inspections~60 min at 8 tabs1 orchestrator, 4 concurrent processes, deterministicA post-condition per record type, checked before the file is written — 207 guest cards were saved as empty shells and had to be re-pulled. Assert index count == detail count. Navigate to a same-origin page before any in-page fetch. The window rule: current year complete, half-open range, undated records dropped never imputed
S5 Documents, templates, settingsSpecificJar; occupancy and property listsExecuted leases, templates, letters, fee schedule, screening criteria, house rules + an index mapping each file to its propertyNew — unmeasured1, deterministicNot done last night — the largest gap. Two traps: the plain document URL redirects to the blank base template (a blank contract was once attached to a customer notice this way); only the download POST returns the executed document — and that POST is a non-GET, so the S1 write guard must allowlist it deliberately
S6 Postprocess, manifest, window auditAgnosticThe raw dumpManifest with a mandatory gaps[] array; window audit20 min1 script + 1 auditor (sonnet)Fix #3. The window audit runs before any analysis — last night ~60 published statistics had to be restated (e.g. "tenants who ever replied by text" 44.6% → 34.8%). Exclusions list at manifest time (a "DO NOT USE" placeholder property carried 17 phantom units). The bot-vs-human actor list is a kickoff-call input, never inferred — one shared VA login looks exactly like a bot
S7 Policy miningAgnosticWindowed message corpus + the PMS's own per-lease settingsPolicy ledger: rule as observed, evidence label, counts, quotes, and the system-configured value beside it40 min1 on opus — judgment: rule vs one-offSitus: 49 topics, 23 stable rules, 12 conflict topics / 27 rows, 5 unknown. The killer move is staff-says vs system-configured: staff quote a flat $50 late fee; AppFolio holds five different schemes across the 485 leases that have one. Neither side is authoritative alone — the conflict list is the client conversation
S8 Property-facts assemblyAgnosticS3 reports + S4 records + S7 stable rulesPer-property fact block20 min1, deterministicEvery inconsistently-quoted value written explicitly as NOT ESTABLISHED. That is load-bearing, not a placeholder: it converts "Clara invented a number" from an invisible pass into a graded failure in S9
S9 Replay dry runAgnosticReal inbound turns that got an individual human reply + the S8 fact blockGraded rows, results, scrub map, 100-row calibration sample40 min for 2,118 rows at concurrency 8Production draft model as subject, judge model as grader — on the subscription; a metered runtime is refusedTwo non-negotiables: in-process prompt replay only (the full harness can dispatch a real send, and these are a third party's residents), and deterministic scrubbing across the whole dump. Result: 56% acceptable, missing-fact 33%, wrong-action 5%, wrong-fact 4%, hallucinated-policy 2%, tone 1%. Run 2, with the full mined knowledge base loaded, returned 56% again — a null result inside a 0–3 point noise floor measured by a control re-run
S9b Question-bank coverage checkAgnosticThe 397-question bank (P0/P1) + the per-property knowledge blocks from S8Per-question answered / missing-fact / wrong, a coverage percentage by tier and property, and a fill list ranked by the inbound volume each missing fact unblocks15 min for 1,062 asks at concurrency 8Production draft model as subject, pinned judge as grader — on the subscriptionThe gate a first client cannot otherwise have — no conversation history exists to replay, so the bank stands in. Two rules: no thread, no resident record, no guest card, so a fact the knowledge base lacks is genuinely absent; and re-run it after every fill step, not once. Situs first run: 27% answered (P0 33%, P1 23%), wrong only 2%, flat across communities — a portfolio gap, not a per-property one
S10 Audit of our own property configAgnosticThe PropFlow codebase + the new client's shapeFindings graded A (will break) / B (will misbehave) / C (tests only) / D (already per-property), each with file:line and fix altitude35 min1 on opusMeasured: A=9, B=32, C=12, D=17. Audit the live repo — the first pass hit a 4.5-month-stale mirror and three findings had to be retracted. Search every module root; a sweep of one lib path misses the files holding the biggest prompt findings
S11 Outputs and handoffAgnosticEverything aboveFact block + stable rules to Clara · missing-facts list to the ingestion backlog · conflicts to the client · baseline to the scoreboard · blockers to engineering · PII-marked data package to the team30 min1 on sonnetNothing ships to Clara that did not pass through the review session

Go-live blockers the playbook must catch (S10 top P0s)

Paired with the hub's 58-item config inventory (16 switches / 30 config fields / 12 knowledge sections across 7 dependency stages). Six of the 58 are source-code edits requiring a deploy — so "turn on property #23" is not yet a form. Portfolio defaults are the fix: tour conventions, follow-up timing, escalation style and the rollout ratchets move to the org tier; the building keeps only what is the building — its number, calendar, mailbox, hours, specials, fees, units, PMS pointer.

3 · What was noise, and what to cut

17% waste on a first-of-kind run, and only ~2.3 h of it is genuine defect rework. The biggest single item was a deliberate scope add, not a mistake.

NoiseAgent-hoursCut or keep
Prior-year pull + year-over-year analysis1.80Keep for sales, cut for operations. Added at 23:05 "just to have it"; correct for the commercial proposal, zero contribution to Clara's context. See D2
Two external literature memos1.43Cut. Commissioned before the corpus was in hand and superseded by the memo written from the actual data. Nothing cites them
Guest-card empty-shell re-capture0.58Cut by guard — a post-condition per record type
Findings-report rewrite after "insanely hard to read"0.25Cut by process — presentation rules stated before v1, not after
Inspections type-bug re-run0.24Cut by guard — assert index count == detail count
Write-guard / double-login / blank-page fetch failures~0.05Cut by guard — pre-set allowlist, PID file, same-origin precondition
Four parallel scout logins that killed each otherCut by rule — one session at a time, always

The pattern: every defect that cost real time has the same shape — no post-condition on a captured record. Empty shells, a bad URL builder, a fetch from a blank page, an aborted render call. Playbook v1 turns each into a guard.

4 · What to load, and what not to

59 entities inventoried across the client's PMS. The verdict, not the volume, is the product of this stage.

VerdictCountMeaning
ONBOARD8Context Clara loads once at onboarding
LIVE-SYNC19Live data Clara reads at runtime — a feed, not an onboarding artifact
ANALYSIS-ONLY25Findings report and replay corpus. Never loaded into Clara
EXCLUDE4Context rot — explicitly do not load
NOT EXPORTABLE3Confirmed twice in this account; stop retrying

ONBOARD — the 8

EntitySourceFieldsVolume at SitusFreshnessWhy
Rent rollReport exportUnit, resident, rent, status10 rowsNightlyCore property facts. Also a sync feed
Rent roll, itemizedReport exportCharge composition per unit721NightlyWhat a resident is actually billed, line by line
Unit directoryReport exportUnit inventory, sizes771One-time + on changeThe unit list Clara answers about
Property directoryReport exportProperty list206One-timeThe properties Clara is configured against
VendorsVendor page + directory exportName, trade, contact1,281On-demandTrade routing for maintenance
Recurring work-order templatesRecurring work-orders pageSchedule, trade, property220 (224 rows)On-demand"When does pest control / filter service happen here" is a real resident question
Stable policy rulesDerived (S7)Rule, evidence label, counts, quotes, configured value23 rulesConfirmed at review, then re-checked on a cadenceThe rulebook. Derived from messages, never the raw messages themselves
Property fact blockDerived (S8)Facts + explicit NOT ESTABLISHED list1 per propertyPer onboardingWhat Clara answers from — including what she must refuse to guess

EXCLUDE — the 4

DatasetVolumeWhy not
Owner directory561 rowsOwner PII. Clara does not answer owners at go-live
Inventory status3 rowsEffectively unused in this account
Inventory usage1 rowEffectively unused in this account
Keys detail1 rowEffectively unused in this account
LIVE-SYNC (19) and ANALYSIS-ONLY (25) — full rows
EntitySourceVolume 2026FreshnessVerdictWhy
Occupancy indexInternal JSON feed3,438NightlyLIVE-SYNCThe universe every other walk is driven from
Tenant / occupancy recordPage + sub-blocks1,418NightlyLIVE-SYNCIdentity, unit, lease dates, balance
Work orders (open)JSON:API + detail page2,588NightlyLIVE-SYNCClara must know what's already in flight
Guest cards (open prospects)Index + detail + conversation panel883NightlyLIVE-SYNCLive leasing pipeline
Rental applicationsIndex + applicant detail + audit timeline90NightlyLIVE-SYNCApplication status is a top-3 missing fact (84 blocked rows)
Renewal rowsFiltered feed143NightlyLIVE-SYNCPhase 2, not MVP
Calendar eventsGraphQL read query825LiveLIVE-SYNCTour booking cannot work without it. Pulled in 28 seconds
Unit vacancy detailReport export212LiveLIVE-SYNCLive availability is the #2 missing fact (102 blocked rows)
Historical advertised rent (current)Report export1,163NightlyLIVE-SYNCCurrent asking rent. History is analysis-only
Tenant directoryReport export1,037NightlyLIVE-SYNCIdentity resolution
Delinquency / delinquency as-ofReport export433LiveLIVE-SYNCThe headline $3.73M owed across 385 tenants is unverified — likely mixes commercial and stale balances
Tenant unpaid charges summaryReport export1,220LiveLIVE-SYNC"Resident ledger line items" is a named missing fact
Security deposit funds detailReport export466On-demandLIVE-SYNCDeposit amount is the single most-repeated individual missing fact
Lease expiration detail / summaryReport export191 / 39NightlyLIVE-SYNCPhase 2
Renewal summaryReport export55NightlyLIVE-SYNCPhase 2
Rental applications reportReport export34NightlyLIVE-SYNCScreening timeline
Upcoming activitiesReport export3LiveLIVE-SYNCToday's schedule
Tenant event historyPage sub-blocks174,619 eventsOne-timeANALYSIS-ONLYThe derived policy ledger is loaded; the raw events never are. This is the single most important line in the table
Email bodiesPer-email fetch93,656One-timeANALYSIS-ONLYReplay corpus + policy mining
SMS threadsPage sub-block32,309One-timeANALYSIS-ONLYReplay corpus + policy mining
Tenant notesPage sub-block1,355One-timeANALYSIS-ONLY49% are truncated in the page itself
Lease / renewal audit logLazy-loaded sub-block45,960One-timeANALYSIS-ONLYWho did what, when — for the baseline, not for Clara
Work orders (closed history)Same feedOne-timeANALYSIS-ONLYVendor track record, not runtime context
InspectionsFeed + detail201On-demandANALYSIS-ONLYExecuted instances only; the template was never reached
Renewal detail documentsLease-document page21 of 143One-timeANALYSIS-ONLYFunctionally useless — every captured text is truncated at exactly 8,000 characters
Gross potential rent, occupancy summary, unpaid balances by month, lease historyReport exports724 / 58 / 481 / 203NightlyANALYSIS-ONLYPortfolio analytics for the findings report
Work order reportReport export2,448NightlyANALYSIS-ONLYRow counts unreliable — the date filter keys the wrong field
Work-order labor summaryReport export28ANALYSIS-ONLY1,442 entries / 1,760 hours, 0 billed — the billback gap
Purchase ordersReport export3ANALYSIS-ONLYPO/invoice sections parsed empty on every work order checked
Guest cards / inquiries / inactive guest cards / showingsReport exports137 / 128 / 400 / 22ANALYSIS-ONLYLeasing corpus
Leasing funnel / agent performance / summary / prospect sourceReport exports33 / 8 / 4 / 29ANALYSIS-ONLYCommercial findings only
Inspection detail / unit inspection / unit turn detailReport exports1,193 / 212 / 952ANALYSIS-ONLYTurn analytics
Box score, property performance, tenant transactions summaryReport exportsNOT EXPORTABLENever exported in either year. Platform limitation in this account, confirmed twice — one of them was retried 113 times against a modal intercepting the click

The 11 exclusion filters — context rot

These cut across entities rather than removing one, and they are separate from the 4 excluded datasets.

Do not loadVolumeWhy
The "DO NOT USE" placeholder property17 units, 0% occupancy, 146 work ordersNot a property. Inflates every vacancy and maintenance number and gives Clara 17 phantom units
Commercial propertiesOffice towers, suites, building-directory threadsWe are scoped to multifamily. Their commercial line stays outside our scope — and the top replay failure was a commercial suite-directory thread
Pre-window tenant historyOnly 72% of texts and 46% of emails fall inside the current yearSurvivor-biased: full history survives only for people still living there. Loading it teaches Clara a skewed past
Bot-authored messagesFour named system accountsThe PMS's automation talking to itself. The trap: one shared VA login looks exactly like a bot and must be kept as human — get this list in the kickoff call
Templated blasts and marketing sends15,408 of 20,686 outbound texts (74%) across 267 templates; one blast alone was 554 textsBroadcast copy is not conversational ground truth — and it swallows real questions: 18% of question-bearing resident texts were "answered" only by the next blast
Failed / undelivered messages1,661 (8.03%)Never reached a human. A data-quality finding, not context
Duplicate co-tenant messagesDeduped on timestamp + first 120 charactersThe same message stored on each co-tenant's record
Owner directory and owner correspondence561 rowsOwner PII; owners are out of scope at go-live
The prior-year dump, in full5,179 files / 142 MBExists for year-over-year comparison only. Never Clara's context
Scout-run outputsFour directoriesSuperseded by the full dump. One exception: the property CSVs are still the only copy of some views
Renewal document text8,000-character truncationsTruncated mid-lease. A partial lease is worse than none

5 · The missing documents

And we already own the capability. The browser-agent repo carries three live-verified document readers the dump toolkit simply never called: an executed-lease reader (proven byte-identical to what the UI prints), a renewal-letter renderer, and a per-document signature-status reader. What last night captured was the pointer — a filename and a link, as scraped text. The link was never followed.

DocumentWhere it lives in AppFolioReachable by the toolkit?Replay gap it unblocks
Fee schedule (application, admin, deposit, pet, parking)Property settings + lease charge config; the published schedule is usually a documentPartly. The configured values were captured and they contradict what staff say. The published schedule document was not reached70 blocked rows — the highest-value document in this table
Application / screening criteriaOnline-application settings; rental-application questionsNot attempted — no path in the toolkit84 rows combined with application status. Fair-housing sensitive: this must be the client's written text, never inferred from staff messages
House rules / community policiesProperty Documents tab, or a lease addendumUnknown — no path, zero hitsNoise, conduct, parking and tow, smoking, guests — all currently inference-only topics in the ledger
Executed leases + addendaOccupancy → Lease DocumentsYes, proven live. Index via the occupancy API, binary via the download POSTLease-terms questions directly; underpins renewals and move-outs
Lease templates / e-sign packetsForm templatesYes — already read by the lease reader's resolverThe template is what makes a portfolio-wide rule loadable instead of 1,418 per-resident reads
Notices & letters templatesLetters & templatesPartly — the renewal-letter render path is provenTone and required legal language for outbound notices
Move-in / move-out checklistsInspection templatesInstances yes, template noMove-out and turn charges; deposit-return questions
Renters-insurance requirementsLease addendum / property settingsNo path attemptedThe practice is well measured (1,297 messages about the monthly liability charge); the requirement is not
Vendor contracts & insurance certificatesVendor record → attachmentsNo path attemptedVendor, pest and inspection schedules — 21 blocked rows
Welcome packetsShared documents libraryNo path attemptedMove-in questions: keys, utilities, laundry, mail
Website content & listing textOutside the PMS — the public listings pageYes, and partly done102 rows — the #2 cluster. And listings sync never runs for any Situs property (blocker above)
Work-order photos & invoicesWork-order attachmentsLinks only — the code comment says "captured, never clicked"Billback evidence

Priority order, by blocked replay rows: fee schedule (70) → application and screening criteria (84, fair-housing sensitive) → house rules → executed leases and templates → vendor and pest schedules (21).

5b · The question bank and the coverage check

A new client has no conversation history with us, so nothing tells us whether the knowledge base we just built is good enough to put Clara in front of their residents. The question bank is the stand-in: ask the questions other properties actually get, against this client's knowledge base, and the gaps come out as a ranked shopping list before anyone is texted.

397 canonical questions — P0 154 / P1 200 / P2 43 — built from 5,465 real inbound turns across two corpora: Situs Group (1,636 apartment turns, 2026) and Camellia Apartments (3,829 turns since April 2026, pulled read-only from production). 1,940 of those turns (35%) are questions; the rest are acknowledgements, greetings and content-free fragments. Every question carries the fact key that would answer it — 112 keys, 89 of them behind at least one P0 question — plus where that fact lives in AppFolio and which document normally carries it.

The fifteen questions properties actually get

TierQuestionMostly asked bySitusCamelliaTotalFact key
P0When can I schedule a tour?Prospect78154232tour.availability_calendar
P0How do I reach a specific staff member?Vendor35457contact.staff_directory
P0What units are currently available?Prospect124052availability.vacant_units
P0How do I request maintenance?Resident262147maintenance.request_process
P0Can I reschedule my tour?Prospect34943tour.availability_calendar
P0What is the property address?Prospect221335property.address_directions
P0What is the status of my application?Prospect26834apply.status
P2[long tail — 34 one-off questions folded into one row]Resident33134other.long_tail
P0How do I reach the front office?Prospect62632contact.phone_main
P0How do I submit a payment?Resident24832ledger.payment_methods
P0How do I access the online application?Prospect16925apply.link
P0Can I set up a payment plan for my balance?Resident21021ledger.payment_plan_authority
P0What payment methods are accepted?Resident15520ledger.payment_methods
P0Who am I speaking with?Prospect31619contact.staff_directory
P0When can I move in?Prospect81018availability.move_in_dates

The top question is 12% of all question volume on its own. Tiers are cumulative share of question volume: P0 is the top 80%, P1 the next 15%, P2 the long tail. Spanish is 5.8% of question volume, carried almost entirely by Situs.

Running it against Situs — the first coverage check

Coverage is flat across the three communities (23–29%), so this is a portfolio-level gap, not a per-property one: the knowledge blocks are built from the same PMS fields everywhere, and the same fields are empty everywhere. Filling one building's gaps fills all thirteen.

The fill list — what to go get, ranked by the inbound it unblocks

#FactInbound volume unblockedWhere it lives
1tour.availability_calendar — the live showing calendar598Not in AppFolio. The showing calendar lives in the leasing tool / staff calendar
2apply.status — application status for this applicant177Applications module + screening settings; guest card; online application
3contact.staff_directory — who is who, and how to reach them147Property → Property Manager + contact fields; vendor directory
4tour.confirmation_process — how a tour gets confirmed145Not in AppFolio. Staff availability + showing policy
5ledger.charge_breakdown — what the charges on this account are126Tenant ledger; delinquency report; late-fee settings
6ledger.balance_due — what this resident owes right now93Tenant ledger; delinquency report
7fees.deposit_security — the security deposit90Charge codes; lease recurring charges; application settings
8availability.vacant_units — what is vacant today, with rents85Reporting API unit-vacancy + unit-directory reports; unit listings
9movein.date_process — when they can move in, and what happens81Lease record move-in date; unit turn status
10vendor.work_order_scope — what the vendor was actually sent to do81Vendor directory; work-order assignment; bills and invoices

A separate long-tail bucket (177 turns of one-off questions with no shared fact) sits between #1 and #2 and is not fillable as a fact. Six of the ten are live system state. The single biggest gap is not a document at all — the tour calendar alone blocks 598 inbound messages, nearly a third of all question volume, and there is no AppFolio field for it. Full ranking in coverage_fill_list.csv.

The fact-key schema — 112 keys

Every question in the bank names the fact key(s) that would answer it, drawn from a controlled vocabulary seeded from the replay's missing-fact list. Each key carries its AppFolio source, its document source, and whether a P0 question depends on it — so the bank doubles as the ingestion schema, not just a checklist.

FamilyKeysFamilyKeysFamilyKeys
apply.*12contact.*5utilities.*4
lease.*10property.*5moveout.*4
fees.*8access.*5pets.*4
policy.*8parking.*5availability.*3
ledger.*7amenities.*5hours.*3
maintenance.*6tour.*4movein.*3
pricing.*4vendor.*4other / escalation / owner3

The keys carrying the most real messages behind them:

Fact keyQuestions using itMessages behind itWhere it lives
tour.confirmation_process14368Not in AppFolio — staff availability + showing policy
availability.floorplans12360Unit vacancy + unit directory reports; marketing listing sheet
tour.availability_calendar6313Not in AppFolio — staff availability + showing policy
other.long_tail60206Varies
hours.office14177Property contact info (partial); office-hours + after-hours doc
availability.vacant_units14173Unit vacancy + unit directory reports; marketing listing sheet
contact.email_leasing16134Property manager + contact fields; staff directory / phone tree
availability.move_in_dates10120Unit vacancy + unit directory reports; marketing listing sheet
Method — how the bank was built, and what it cannot see

Corpora. Both scrubbed locally before anything reached the deliverable. Situs Group: 1,636 inbound turns, 2026-01-01 → 2026-09-01, multifamily only (16 apartment properties / 397 units), from the de-duplicated turn set the replay already used. Camellia Apartments: 3,829 turns, 2026-04-01 → 2026-09-02, pulled read-only from the production table through the same read pattern as the existing prod-corpus harness. Names, phones, emails and dollar balances substituted locally.

From messages to canonical questions. Every inbound turn is tagged — is this a question, what is the underlying ask in generic phrasing, who is asking, which fact key(s) would answer it — on claude-haiku-4-5 at temperature 0, on the subscription. 1,940 of 5,465 turns (35%) are questions. Raw phrasings are then clustered twice within each fact key (1,707 → 756 → 451), capped at 6 questions per key, then counted across both sites and tiered by cumulative share of volume. P2 questions seen exactly once are folded into one long-tail row per fact key so the bank stays a working checklist. Final: 397.

What the checker does. For each question it renders Clara's production drafting prompt, read at run time from the leasing eval config, with the resident persona swapped in on resident questions, the property's knowledge block loaded as a cached system block, and no thread, no resident record and no guest card — so anything the knowledge base does not carry is genuinely absent, which is the point. A pinned judge then labels the reply answered (specific, actionable, supported by the knowledge base), missing-fact (a graceful "let me check" is still a gap), or wrong (asserted a fee, policy, amount or timeline the knowledge base contradicts or never mentions). Subject model resolves from production resolveDraftParams(channel); judge is the pinned EVAL_JUDGE_MODEL. Everything runs on the subscription; the runner refuses a metered runtime. It uses the in-process replay tier — there is no code path in it that can dispatch a send.

What we cannot see.

External research — what the industry says people ask, and why we did not lean on it

The questions themselves were collected from public renter FAQ pages, ILS "questions to ask" guides and AI-leasing-vendor material — Apartment List's 36 questions, Greystar tour questions, Zillow and Zumper tour-scheduling pages, Camden and AvalonBay pet FAQs, HUD assistance-animal guidance, EliseAI and Zuma product pages — grouped into 18 topics from availability and tours through screening, fees, pets, parking, utilities, amenities, lease terms, move-in, maintenance, emergencies, payments, renewals, move-out, community rules, accessibility and vendors. Every row cites its source; nothing was invented.

The frequency claims, all carrying the caveat above: roughly 60% of calls to leasing offices are pricing-and-availability inquiries; leasing inquiries are 20–25% of total call volume; ~49% of calls to leasing offices go unanswered; a reply within 5 minutes makes a lead 21× more likely to convert than one at 30 minutes; 60% of prospect communication is phone, 22% email, 18% text; ~87% of callers who reach voicemail leave no message. The best-sourced number in the set is the NMHC / Grace Hill 2024 Renter Preferences Survey (172,703 respondents across 4,220 communities: in-unit washer/dryer and A/C each a must-have for 93%, high-speed internet 90%).

Where it says our bank is blind. Six categories skew to phone and are therefore under-sampled by a corpus built mostly from written channels: compound conversational pricing questions ("month-to-month vs 12, and does that change the deposit?"); emergency maintenance (flood, no heat, lockout); candor questions ("would you live here?"); neighbourhood and safety questions; callers who hang up rather than leave a voicemail, who become no record at all; and fair-housing accommodation requests, which are typically raised verbally first and only documented afterwards. The Camellia half of the corpus is voice-heavy and partly covers the first two; the rest is a known hole in the bank.

6 · The review session — UX

The customer's job is disposition, not authoring, and most facts never reach them at all. Consolidation runs first, unattended; the human sees only what the data cannot settle.

Consolidation before review — what never reaches a human

A raw extraction produces hundreds of candidate facts per portfolio (Situs: 112 fact keys × 16 properties, plus every message-mined restatement). Reviewing them one by one is the queue we refuse to build. Five rules, applied by the pipeline with no human in the loop, decide almost all of them:

#RuleEffect
1Documents and system settings auto-confirm. A fact stated in a lease, a letter template, or an AppFolio setting is CONFIRMED with the document as its evidence. No card.Late fee, NSF fee, month-to-month premium, renewal credit, insurance charge — settled from the documents pull, never asked.
2Message-mined facts auto-confirm above an evidence floor. At least 5 messages from at least 2 staff, no contradicting statement, no contradicting document → CONFIRMED. Below the floor → held as UNCONFIRMED. Clara does not act on it and nobody is asked to confirm it; it surfaces only if a live conversation needs it (section 7).The "Confirm" queue disappears. Low-evidence facts cost zero review minutes.
3Dedup across properties. Values are normalized (amount, unit, wording) and compared. Same at every property where evidenced → one portfolio-level fact, zero property rows. A property gets its own row only where its value differs. A fact seen at one property only is a portfolio fact tagged "seen at", not an override.One card per fact, never one per property. Sixteen identical late-fee rows become one.
4Live state is never a fact. Vacancy, balances, unit status, application status are PMS pointers read at runtime. They are excluded from extraction, so they cannot appear in review.Removes the largest class of junk from the first Situs build (unit snapshots presented as knowledge).
5Missing is not a card. A key with no evidence anywhere goes to the fill list (5b) or the integrations lane (D9). It is never presented as a blank for the customer to type into.Blank-page authoring never happens; the customer is not asked to write a policy book.

What is left for a human is exactly one thing: conflicts — staff vs staff, staff vs document, document vs system setting — plus the rare outdated item where a document contradicts a current setting. On the Situs data that is 13 conflict topics against 112 keys. The review is a 20-minute session, not a project. When the queue is longer than a coffee, the pipeline is wrong, not the customer.

Evidence floor and dedup are the same rules the "What Clara knows" page is built from, so the review queue and the brain page are one dataset with two views.

Ten principles

#PrincipleSource
1Pre-fill, never blank-pageEliseAI's knowledge setup — prefilled from the property's own website before the customer opens it
2Every claim carries its evidence inline — quotes, counts, dates — not a bare scoreGlean's citation-over-badge model; Notion Q&A inline citations
3Conflicts resolve field-by-field against a named base, not message-by-messageMaster-data survivorship (field-level) + git three-way merge
4Batch by decision type, keyboard-first for the easy stuff; slow down only for conflictsProdigy / Label Studio accept-reject-ignore; Linear Triage single-key actions
5Decline or skip must ask why, or offer snooze — never silently discardLinear Triage: decline requires a reason; snooze preserves state
6Ownership and a re-check cadence attach to every accepted itemGuru verification cadence; Confluence stale-page automation
7Every accept, reject or edit writes an audit entry — who, when, before, afterConfluence Page Review Manager; Palantir ontology proposals (branch → review → merge)
8Corrections are training signal, not one-off fixesChatbot escalation-log training (directional); Ramp/Brex pattern learning (marketing-sourced, low confidence)
9State explicitly when there isn't enough evidence — never guess and present it as factNotion AI's "I couldn't find enough information" behavior. This is NOT ESTABLISHED surfacing in the UI
10Watch reviewer behavior for decay (approval rate → 100%, latency → 0) and treat it as a queue-design bug, not a customer failingApproval-fatigue literature

Information architecture — portfolio first, property as an override

Topic-first buries the handful of items that actually need a human inside hundreds that don't. Property-first repeats the same fact sixteen times. The tree is portfolio-first; a property is a filter that shows only where it differs from the default.

Portfolio
 ├─ Needs You (2 types, badge-counted)
 │   ├─ Conflict (staff vs staff, staff vs document, document vs setting) — scoped to the properties where it occurs
 │   └─ Outdated (a document contradicts the current system setting)
 ├─ Policy Book — portfolio defaults (auto-confirmed, browsable by topic)
 │   └─ Overrides table: fact × property, only where the value differs
 └─ Property view (e.g. "Carr Street Flats") = defaults + this property's overrides + its open conflicts

"Confirm" and "Missing" are gone from the human tree on purpose: confirm is decided by the evidence floor, missing goes to the fill list. Intercom Fin's four-way taxonomy (missing / unclear / duplicated / contradictory) still applies, but three of the four are handled by the pipeline.

Card anatomy, and the conflict view

┌─────────────────────────────────────────────────────────────┐
│ CONFLICT · Late fee grace period            [Applies to: ▾]  │
│                                              Willows only ▾   │
│ Staff says the grace period is either 3 days or 5 days.      │
│                                                                │
│  Variant A — "3 days"            Variant B — "5 days"         │
│  ────────────────────            ─────────────────────        │
│  "we always give a 3 day        "our policy is 5 days,        │
│   grace window"                  we've never enforced          │
│  — Erika, text to tenant #4021   day 4"                        │
│  Aug 14, 2026 · 1 of 6 msgs      — Darrin, staff Slack          │
│                                   Jul 2, 2026 · 1 of 2 msgs     │
│                                                                │
│  System setting (AppFolio): late_fee_grace_days = 5           │
│                                                                │
│  Recommended: Variant B (matches system, more recent, 3       │
│  independent mentions vs 1)                                    │
│                                                                │
│  [ Keep A ]  [ Keep B ✓rec ]  [ Something else… ]  [ Skip ]    │
└─────────────────────────────────────────────────────────────┘

Every card carries: the claim in one line; evidence quotes with speaker, source, date and corroboration depth ("1 of 6 msgs"); a confidence label, not a number ("3 independent mentions"); the system-of-record value where one exists; a recommendation with its reasoning stated; and a scope selector — this property / these properties / whole portfolio — defaulted to the narrowest, so a correction never silently propagates.

Conflicts always show two or three named, attributed variants side by side. Base = the system of record when there is one, otherwise the better-corroborated variant leads. Anonymized conflicts cannot be resolved with judgment.

Batch and keyboard flow

Documents, audit trail, end state

Upload triggers scoped re-derivation. A property can upload a lease template, house rules or fee schedule at any point. That runs the same agent pipeline restricted to the claims the document touches, and re-opens only the affected cards. Never a full portfolio re-run. Uploaded documents outrank message-mined evidence and carry an "Official document" badge — but if the document conflicts with what staff actually do, that surfaces as a variant, because the gap between the written policy and the practiced one is itself a finding.

Audit trail. Every disposition writes item id, before-value, after-value, decision type, reviewer, timestamp, scope, and whether the customer took the recommendation or overrode it. Browsable per property, filterable to overrides only — the fastest way to spot a review decaying into rubber-stamping.

End state: one policy book for the portfolio, with a per-property override table. Every resolved item organized by topic, each showing its evidence, its resolution, who confirmed it and when, and its next re-check date. That is what Clara reads. Nothing enters it without a disposition; skipped items stay in Needs You until they are resolved or their snooze expires.

What not to build

7 · North star — Clara calls and asks

Same four decision types, same evidence-and-recommendation structure. Different order and phrasing, because a call can't show a side-by-side card.

8 · Decisions for Fede

D1 · Where the playbook lives

Why: the consumer of every playbook output is Clara's property config, which lives in the product — where the onboarding wizard, credential delegation and property import already ship. And auditing our own Camellia assumptions is inherently a product-repo job, because it reads that repo's own prompts. No new repo; revisit only when a real Yardi or RealPage adapter exists in code.

D2 · Scope of the standard pull

D3 · What gets loaded into Clara by default

D4 · Review UX, first version

D5 · Documents

D6 · Data use — resident messages as eval material

What we did last night: internal replay only, deterministically scrubbed across the whole dump through a hand-verified substitution table, in-process prompt replay with no send path. Nothing was sent to anyone and nothing left our machines. The data package is PII-marked and owner-only.

D7 · The turnaround promise in the pitch

Say "overnight" and deliver in a few hours.

D8 · One PMS login per client, or the shared PropFlow login

Sessions are per database, and a clean test on Sep 2 (fresh profile, second login, both sessions probed at 10, 60 and 180 s) showed a second login does not invalidate the first; the Sep 1 collision came from cloned browser profiles sharing one cookie jar. So this decision is about lockout, audit and revocation, not session collisions. Becomes stage 0 of the playbook: the client creates the user before the overnight run.

D9 · Onboarding order: integrations before documents

Two measurements landed on Sep 2 and they point the same way. Replaying 1,625 real Situs turns with a full mined knowledge base loaded moved the acceptable rate from 56% to 56% — a null result inside a measured 0–3 point noise floor. And the question bank, counted from 5,465 real inbound turns, finds 64% of question volume needs live PMS data, not a static fact sheet. The single largest gap is the live tour calendar, which alone blocks 598 inbound messages and has no AppFolio field at all.

The null result is not an argument against the knowledge base — missing-fact still fell 33% → 30% and 105 rows were fixed by it, and it caught Clara inventing unit availability that run 1 could not see. It is an argument about order: the documents pay off, but only once the live feeds are underneath them.

9 · Next steps

10 · From client answers to the knowledge base (2026-09-15)

Proposed — pending Fede's review · 2026-09-15

Where we are today

Western Slope finished the in-product review this morning: 26 of 26 items answered by Jay — 6 corrected, 4 open/conflict questions answered, 16 confirmed.

Correction 2026-09-15: the apply step merged with a write target Fede had not confirmed (anchor property). Nothing was written anywhere. Re-targeting to company + building is the next PR chain; the walker PR was stopped before opening.

Target flow — the goal is autopilot, not a hand-run playbook

Fede, 2026-09-15: onboarding should scale to people self-signing up, with no engineer running steps by hand. Five moments:

  1. The customer signs up and connects AppFolio in the wizard. A new wizard step asks them to add Clara as a user in their AppFolio — each client gets its own Clara login (see D4), so one lockout or rate limit never takes every client down. That login is the second dependency, alongside API access.
  2. Once both dependencies are present, a background job starts on its own. A deterministic script — not agents — makes the AppFolio API calls and pulls the raw data: units, listings, guest cards, maintenance, lease templates, documents. The browser agent is used only where no API exists. This takes hours; that's fine.
  3. The customer sees one line: "We're setting up your organization — you'll get an email from us in a few hours to confirm a few things."
  4. The job builds the operations map and the knowledge draft (Camellia shape: 12–20 leasing-only items), creates the review, and the confirmation email — review link and password — goes out. Held for a human at first: Fede reads the draft before it sends. Once two companies have gone through cleanly, this step goes fully automatic.
  5. The customer answers. When every item has a verdict, the review flips to done, the apply step writes the knowledge base (held-out items listed, never written silently — see below), and a one-line summary goes to #updates-fede.
  6. Verify live equals the gold set, then bench every exception. Run npm run knowledge:verify-live -- --gold <gold-set.json> --property <front-door-property-id> against production; it must print 0 missing, and that output is the tracker row's evidence. Then place one bench call per property exception on phone, text and email (scenarios knowledge-exception-* in scripts/voice-harness/scenarios/) and confirm Clara answers from the exception, not the company rule.

Three small, dark PR chains

1 · Kick-off, on AppFolio access (build first alongside the apply step — Western Slope needs the apply half by Thu Sep 17; kick-off targets the next new company)

When a company's AppFolio credentials are stored (wizard finish) and the Clara user exists, a job runs the discovery phases (units, listings, guest cards, maintenance, lease templates) by deterministic API script with the browser agent as fallback, builds the operations map and the Camellia-shaped knowledge draft, and creates the review in "draft" status with a link and password. First: draft held until Fede has read it and sends the email. Once two companies have gone through cleanly: sent automatically, Fede on copy.

2 · Apply step (this week — needed for Western Slope go-live Thu Sep 17)

A script/job apply-knowledge-review reads a finished review and writes knowledge sections: Correct → the proposed text becomes the section; Wrong + correction → the correction, rewritten in Clara's voice, replaces it; Answered → the answer fills the open question. Company-wide policy goes to org-level knowledge, a fact about one home/building goes to that building (Gera's portfolio model). Each section records who answered and when. Idempotent, re-runnable, prints a before/after diff.

Items that need judgment are held out and listed, never written silently:

The first run is reviewed by Fede as a before/after page; later runs go straight in and post the diff to #updates-fede.

3 · Close the loop

When every item has a verdict the review flips to done (today status stays "open" forever), the apply step runs, and a one-line summary with the held-out items goes to #updates-fede. Held-out items that need the client's answer become one short follow-up back to the client (sent by Fede).

Decisions for Fede

D1 · Where the apply step writes DECIDED 2026-09-15

D2 · First-run gate DECIDED 2026-09-15

D3 · Kick-off gate for new companies

D4 · Per-client Clara AppFolio login

11 · What we learned onboarding Camellia, Situs and Western Slope (Sep 5–15)

Proposed — pending Fede's review (2026-09-15)

Rulings that are now standing rules

DateFede's words (shortened)What it means for the playbook
Sep 5Western Slope up fast on infra we have; Situs can take longerNew clients don't all move at the same speed — the playbook has to work for a fast, simple client and a slower, harder one
Sep 7"we should just call APIs" — no Playwright unless there's no APIRaw pull is a deterministic script; browser agent only where no API exists (stage 3)
Sep 7Situs and Western Slope "are separate companies"No cross-client knowledge sharing, ever — separate orgs, separate knowledge bases
Sep 9"wtf i never asked for a suggested link feature" — autonomous, no merge buttons everThe knowledge build never asks a human to click merge/confirm on routine matches — it decides, and a wrong decision gets fixed in the engine
Sep 8"this is an insane slop ball" — split policy / listing fact / internal-only / settingsEvery knowledge draft uses Camellia's shape and that four-way split, not a flat question list
Sep 8"we just collect free-form, and when we inject it into the system, we decide how we structure"Clients answer in plain language; PropFlow's build step does the structuring
Sep 7"since we're adding customers in the back office, we should be setting the PMS" not asking the clientPMS choice is a PropFlow staff step, never a client-facing wizard question
Sep 12Bulk first-time import is a different job from day-to-day pollingRaw pull is a one-time onboarding job, not the same code path that keeps a live client's data fresh
Sep 16Import window (Fede, 2026-09-16 evening — in progress)The import keeps only guest cards and applications received in the last 30 days by AppFolio's own date, open or closed; rows without a date are dropped. The every-minute sync creates no new record older than 30 days either, but keeps updating records it already has. Before this, open records were kept at any age: Western Slope's first pull brought 1,065 guest cards (762 older than 90 days) and 145 applications (110 older than 90 days); those are being cleaned up.
Sep 11"I told you to do a full end to end QA" — a partial pass isn't QAEvery stage needs a real end-to-end proof (a live review answered, a live email sent) before it counts as done
Sep 11Clara never quotes income limits, decides eligibility, or states a blanket "no assistance animals" ruleHeld-out rule: anything that touches fair housing goes to a human, never auto-written into knowledge
Sep 15Questionnaire goes to hello@propflowai.co first, for us to check, before the client sees itToday's priority #1 — see section 13
Sep 15Client self-signs up, connects AppFolio, and adds Clara as a user in their own AppFolioOne Clara login per client (decided 2026-09-08) — the wizard, not a PropFlow engineer, collects it

Mistakes we will not repeat

Learnings from the Western Slope knowledge day (2026-09-15)

  1. One record per customer from the first hour. A hand-typed placeholder on Sep 5 and a real record on Sep 12 left two copies of the same company for ten days; nothing in the database or in Gera's model refuses that today. Cost: a full afternoon to inventory and delete 2,049 rows. Rule: the first pull creates the real company under its AppFolio database name, and no session creates a second one by hand.
  2. The questionnaire is the decision. Once the client answers, we stop debating with our own history ($32 charges vs their $40). Flags go back to the client only when their own answer contradicts itself.
  3. Know what the platform already does before asking the client anything. The draft asked how prospects book tours. Clara books tours. Check the client's own sent mail and guest cards first; "how do people apply" turned out to be a per-home button in AppFolio, not a link.
  4. Name the data source before reasoning about it. "Rent roll" on the placeholder was a public-page scrape, while the real company had AppFolio's feed all along. Half an hour of wrong conclusions came from not checking which job wrote the rows.
  5. Entries are facts; Clara does the talking. Scripted lines ("tell me which home and I'll give you the amount") read wrong to Fede in seconds. Facts, short, one figure per line, property exceptions in their own table.
  6. Never hand Fede a link before the deploy is green. Three edits pushed in three minutes cancelled each other's deploys; he read the stale first draft twice and lost trust in the page. Watch the deploy, then send the link, once.
  7. Subagents draft without product context. Every review page a subagent writes gets a pass against the writer rules and the platform's abilities before it reaches Fede.
  8. Delete with a backup and a checklist. What blocked the placeholder delete was not the data but what pointed at it: a shared company id, a workflow that re-created it on every push, a daily test job, a rollback agent. Inventory those first; the delete itself took 20 minutes.
  9. 2026-09-16 — Approved knowledge landed only half loaded. The gold set's 17 company facts loaded; the 7 home exceptions never reached what Clara actually reads, and nobody had compared the live render against the approved file — "knowledge reviewed" meant the client approved the file, not that Clara reads it. On a live call Clara said Ridgway tours are in person; the client had said lockbox-only. Root cause: the loader only knew how to place company-level facts, and no command diffed live output against the gold set. Rule: the loader places every approved fact (company or the home it names) and refuses to finish if a fact has nowhere to go; a verify command renders exactly what Clara reads and diffs it against the gold set before "knowledge reviewed" counts as done.
  10. 2026-09-16 — Western Slope: the 17 company facts loaded, the 7 property exceptions never did, and the tracker said "knowledge reviewed". Clara told a caller a lockbox-only home had in-person tours. Fix: scripts/knowledge/load-knowledge-gold-set.ts places exceptions on the property row and refuses to finish with any unplaced; knowledge:verify-live diffs what Clara reads against the approved file; the onboarding harness (scripts/onboarding-harness/knowledge.ts) runs create → load → verify red-before/green-after on a scratch org. "Reviewed" is never "loaded"; only the verify output counts.

Western Slope onboarding — what went wrong and the rule that prevents it (2026-09-17)

Every row below happened between Sep 7 and Sep 17 while standing up one new client. The rule column is what the next onboarding does instead; the last column is where the rule is enforced, so it survives this page.

Symptom — what the client or Fede sawRoot causePrevention ruleWhere it lives now
On a live call Clara said a lockbox-only home shows in person.Only the company-level facts loaded; the seven per-home exceptions had nowhere to go, and nothing compared what Clara reads to the approved file.Load every approved fact or refuse to finish, then diff what Clara reads against the approved file before "knowledge reviewed" counts.Checklist step "knowledge live"; loader refuses unplaced facts; knowledge:verify-live
A test call got the old draft office hours after the client's answers were approved.The knowledge write had not propagated, and hours were also answered from a stale structured field nobody read back.One structured field is the source of truth for hours; the spoken sentence renders from it, and it is read back live after every knowledge write.Checklist step "read back hours"; officeHours on org and property; platform default 9–5
Evening and weekend tour requests were refused as if the office were closed.Tour slots read reception hours instead of the hours the client will actually show homes.Touring hours are their own setting, separate from office hours, falling back to office hours only when unset.Setting tour.hours; checklist reads both back
Staff tour emails silently stopped mid-morning on the client's live test day.A change put staff notices behind the company-live switch; the company row had no live value, so every non-PropFlow recipient was suppressed.The company-live switch holds prospect outbound only. Staff and team notices are never held by it.One outbound-email seam, one audience decision; checklist proves a booking end to end
Sessions reported "staff email is on" for days while the client received nothing.The evidence used was a config resolver's answer and a delivery to a test property, not a delivery to the client."Email on" means a delivered event to the client's real address with a timestamp and a message id — never a resolver dry-run or a row field.Checklist step "one robot booking → delivered event"
The client's whole delivery log was empty for the entire onboarding.A shadow/redirect switch left over from setup had been rerouting every staff notice away from the client since day one.No shadow, redirect or test-mode switch may exist on outbound staff email; delete them rather than gate them.Shadow-mode reads deleted; checklist reads the delivery log filtered to the client's domain
Team tour notices landed in a PropFlow engineer's smoke mailbox.The front-door property's notice address was still the setup test mailbox, and a wrong "never mail the company's own inbox" rule blocked the correction.Every notification and escalation address points at the client before the first live call; the client's own connected mailbox is a valid recipient.Checklist step "notice addresses read back"; property-level staff-notice recipient setter
Tour notices for 69 of 70 homes reached nobody.Recipients resolved only from a per-property email address that scattered single-family homes never have.Notice recipients fall back to the company's escalation contact; no home may end go-live without a resolved recipient.Org fallback shipped; checklist asserts a recipient for every property
100 "new application to review" emails hit the client's inbox in one hour.The first import brought years-old guest cards and applications, and an hourly reminder job had no age cutoff.Import and sync only create records dated within the last 30 days, and any reminder backstop is opt-in and off by default.30-day import window and sync cap; reminders opt-in
Repair callers were handled by Clara instead of the client's own call center.The forward rule lost to the "we know this caller" rule as soon as caller recognition filled in a name.The client's own intake route outranks caller recognition, and a forward is a plain transfer — never an automated key-press through someone else's phone tree.Setting maintenance.intake_route; prompt fence plus a live replay before merge
Every call on every customer's line failed for nearly two hours.A dynamic field in a phone tool resolved to an empty string, and the voice vendor rejects the entire tool set when one required field is empty.No dynamic voice field may ever resolve to an empty value; the dark path is asserted by a test, and a voice regression is reverted first and re-landed second.Test: the dark state is a real call, no tool field may hold an empty variable
A call to the client's own number reached Clara with no property context at all.A company-scoped routing record short-circuited the property lookup instead of falling through to the property map.Only a property-scoped routing record may short-circuit a lookup; anything company-scoped falls through.Checklist step "bench call on the real number reads back org, property and homes"
Clara quoted an invented "deposit is one month's rent" rule and was wrong on most homes.A portfolio-wide sentence written into knowledge outranked each home's own published figure.Per-home figures come from the listing; knowledge holds only the rule and never a figure that varies by home.Knowledge-writer rules; graded bench calls per home
The client's shared leasing mailbox could not be connected — three failed attempts over days.The Clara account had been added to the mailbox without Full Access and Send As.Mailbox permissions are granted and proven by one read and one send before the connect step, not discovered during it.Checklist step "mailbox connect proof"
Not one lead email ever produced a guest card.All of the client's lead mail was listing-site relay mail; the PMS's own guest-card notification had never been switched on at the client.Clara replies only to guest cards that come from the PMS, and switching on the PMS's guest-card notification is a named setup step at the client.Checklist step "PMS guest-card notification on"
Nothing about the client — calls, tours, digests — ever reached the team's Slack channel.No activity channel was set, and once it was, the app addressed the channel by name and the channel got renamed.Register the activity channel by its permanent id, and prove it with one call that posts.Checklist step "one call posts to the channel"
A tour Clara confirmed on the phone never appeared on the leasing agent's calendar.A stale pinned calendar connection returned an empty token and nothing retried, refused or alerted.A calendar write that cannot resolve a live connection fails loudly, and every calendar-affecting write is verified through the calendar's own API, never from our row alone.Dead-connection fallback with an alert; checklist verifies the booked event
Back-to-back test calls greeted the caller with the previous persona's name, and a repair note leaked into a leasing email.Every bench persona dialed from one number, so caller recognition merged them; a shared free-text note field is written by unrelated parts of the product.One caller id per test persona, never a real person's number or mailbox as a test identity, and no shared free-text field carried between unrelated flows.Per-persona bench numbers; stale-note guard, note field being retired
Twelve empty tour records appeared in production.An update path wrote a placeholder row when the tour it was updating did not exist.An update never creates: a write against a record that is not there fails instead of minting a stub.Upsert guard on the tour writer
Nothing PropFlow decides could be written back into the client's PMS.The browser robot's account list for the new company was drafted and never applied, and the front-door property has no PMS property behind it to write to.Before any write-back is armed, the robot account is applied and proven with one login, and every front-door property has a PMS mapping or an explicit no-write rule.Checklist steps "robot login proof" and "front-door mapping"

Pull requests behind these rules: 7919, 7962, 8007, 8043, 8060, 8314, 8375, 8378, 8458, 8553, 8606, 8638, 8704, 8726, 8750, 8844, 8861, 8882, 8893, 8900, 8912, 8913, 8923, 8927, 8934, 8958, 8962, 8964, 8968, 8969, 8970, 8973, 8977, 8978, 8979, 8980, 8986, 9013, 9031, 9036, 9046, 9047, 9098, 9103, 9105, 9113, 9135, 9137, 9139, 9140, 9144, 9148, 9155.

12 · The repeatable playbook

Proposed — pending Fede's review (2026-09-15)

StageWhat happensOwner todayOnce automatedProof it's done
ProposalClient agrees to onboard; a rollout-timeline page is sentFedeFede (sales stays human)Proposal page sent, client replies
AppFolio access + Clara loginClient connects AppFolio and adds Clara as a user in their own AppFolio (one login per client)Client, with Fede walking them through itA wizard stepCredentials stored; Clara's user confirmed in the client's AppFolio
Raw data pullUnits, listings, guest cards, maintenance, lease templates, documents pulledAd hoc script, by handDeterministic API script, browser-agent fallback only where there's no APIPull manifest with a gaps[] list, no writes
Mailbox + calendar connect, mailbox auditLeasing mailbox and calendar connected, with a scripted audit of the inbox. Owned by the shared-mailbox lane — see the go-live tracker row ws-shared-mailbox-access-gap-2026-09-15 (docs.propflowai.co/a/western-slope-go-live) and the design section docs.propflowai.co/a/email-architecture-2026-08-14#inbound-lead-flow-2026-09-15.By hand, per clientSame wizard step as AppFolio; audit runs automaticallyThe audit section on the client's go-live page — see Western Slope's leasing inbox audit
Operations map + knowledge draftCamellia shape, 12–20 leasing-only items, split into company policy / building fact / internal-only / settingsAgents, hand-assembled and hand-reviewedThe same job that ran the raw pullDraft matches the Camellia-shape item count and split
Questionnaire review created + sentReview goes to hello@propflowai.co first for us to check, then to the clientNot built yet — today's #1 priorityAutomatic after two clean company runsEmail at hello@, then at the client's inbox
Client answers + "I'm done"Client works through the review, then submitsClientClient (this stays human)"Done" status + submitted event fires
Automated knowledge buildAnswers become Clara's knowledge, org-level or per-property per the client's setupA person hand-edits the record from an exportThe event-driven consumer job (section 13c)Before/after diff, held-out items listed, never silent
Verify Clara reads the approved knowledgeRun the verify command against the approved file (renders exactly what Clara reads, diffs it against the gold set). It must be green: every approved fact present, every home exception tied to its home. Then one bench call per exception, on phone, text and email, answered from the exception, not the company rule. "Knowledge reviewed" isn't done until this step is green.Not built yet — loader shipped 2026-09-16, verify command in flightRuns automatically after every knowledge buildVerify output pasted on the go-live tracker row as prod evidence
Hooked-up testsBasic checks that the build actually wired in and Clara can answer from itNot built yetA smoke run after every knowledge buildPass/fail posted to #updates-fede
Dark rollout → Willows-style dry runs → go-liveFeature ships off; dry runs at a test property; Fede turns it on for the real clientFede, per the standard rollout playbookSame — this step stays Fede's callGo-live tracker row moves from untested to proven

Pre-go-live checklist — one line of proof each (added 2026-09-17)

Every step below exists because Western Slope's go-live hit the matching failure in section 11. A step is done when its proof artifact is pasted on the client's go-live tracker row — not when the code merged.

#Checklist stepProof
1The client's PMS access and the browser robot account for their database are applied, not drafted.One successful robot login against the client's database, timestamped
2Every front-door property has a PMS property behind it, or an explicit rule saying nothing is written back.The mapping read back per property, or the no-write rule on the tracker row
3The client switches on their PMS's own guest-card email notification.One guest card arriving in the connected mailbox
4The leasing mailbox is connected with Full Access and Send As already granted.One read and one send through the connection
5The calendar is connected and a booked event is verified through the calendar's own API.Bench booking, then event found; cancel, then event gone
6Approved knowledge is loaded, company facts and per-home exceptions both.knowledge:verify-live against the approved file — zero missing, zero unplaced
7One bench contact per home exception, on phone, text and email, answered from the exception.Three transcripts per exception
8Office hours and touring hours are both read back from the live record.officeHours and tour.hours printed for org and property
9Every property resolves a staff-notice recipient, and every notice and escalation address is the client's, never a PropFlow test mailbox.Resolved recipient listed per property, all on the client's domain
10One robot booking produces a real staff email at the client.A delivered event to the client's staff mailbox — timestamp and message id
11No shadow, redirect or test-mode switch exists on the client's outbound email.The delivery log for the client's domain, non-empty, with no redirected recipients
12The company-live switch holds prospect outbound only; staff notices go out regardless.One held prospect message and one delivered staff notice, same day
13A bench call on the client's real number reads back the company, the property and the homes.Call context printed, no empty fields
14Repair calls leave on the client's own intake route, including for a caller Clara recognises.One recognised-caller repair call forwarded, no work order created
15No voice tool field resolves to an empty value on the dark path.The empty-variable test green on the client's agent
16The import brought only records dated in the last 30 days, and reminder backstops are off.Import count by age; reminder setting read back as off
17The team's activity channel is registered by permanent id.One call posting into the channel
18Every bench persona dials from its own number, and no test identity is a real person's number or mailbox.The persona-to-number list used for the go-live round

How a session uses this

Start here: this page. The go-live tracker (docs.propflowai.co/a/western-slope-go-live) is the status board — every stage above should have a row there once it's wired for a client. The scripts to know by name: the appfolio-onboard tool/skill for the raw pull, load-knowledge-base.ts and export-knowledge-base.ts for the review record, and apply-knowledge-review (PR #8650) for the knowledge build. No new doc page — updates to this playbook go here.

What the mailbox audit feeds

Proposed — pending Fede's review (2026-09-15)

The audit's output feeds knowledge, shared parsing code, and a client ask. Owned by the shared-mailbox lane — see the go-live tracker row ws-shared-mailbox-access-gap-2026-09-15 (docs.propflowai.co/a/western-slope-go-live) and the design section docs.propflowai.co/a/email-architecture-2026-08-14#inbound-lead-flow-2026-09-15.

13 · Build now for Situs Group

Proposed — pending Fede's review (2026-09-15)

Situs Group is next: 645-ish units, no AppFolio API access (browser-only), full 2025/2026 raw dumps already sitting in ~/situs-data, no org/property in prod yet, shared AppFolio login with JP&Co today. Ranked in Fede's stated priority order, each a small dark PR (≤300 lines):

(a) Questionnaire auto-generated from the raw pull, emailed to hello@ first — highest priority

Reuses: the Camellia-shape draft format, load-knowledge-base.ts, the review page/gate. Missing: the job that turns a finished raw pull into an operations map and knowledge draft on its own, and the "create review + email hello@" step. Proof: a review auto-created in draft status for Situs, and the email lands at hello@propflowai.co.

PR chain (scoped 2026-09-15, building):

  1. Generator script: raw AppFolio pull → deterministic fact pre-pass → background-lane LLM → 12–20 item draft in the Camellia shape → seed the review (dry-run default) — in progress
  2. Send-for-check: one internal email to hello@propflowai.co for a freshly created review, recorded once so it never repeats
  3. One command that runs pull → draft → review → hello@ email
  4. Automatic trigger when a company's AppFolio credentials are stored and its Clara login exists, off by default until two companies have gone through cleanly

Engineering choices taken on the lane's recommendation (internal, no customer effect): the draft is a file fed to the existing loader, not a new table; script first, Lambda only if the automatic trigger needs it; the customer-facing "we're setting you up, you'll hear from us in a few hours" message ships with PR 4, not before.

(b) "I'm done" submit + event — in flight (second PR being built)

Reuses: the review page's answers API. Missing: the PR itself — done status, submitted event, internal email to hello@. Proof: a test review flips to done, the event fires, hello@ gets the email.

(c) Consumer job that builds the knowledge base from the event

Reuses: PR #8650 (apply a finished review to the knowledge base, dry-run default, held-out rules). Missing: wiring it to fire on the submitted event instead of being run by hand. Apply runs directly from the submit click, writing company + building per Gera's model; depends on the company-level read path going live first. Proof: the dry-run diff appears automatically on a test review's "done" event and matches a hand-run apply.

(d) Hooked-up smoke tests

Reuses: the existing smoke-test pattern; the question-bank coverage check from section 5b as the shape. Missing: a per-org check that a knowledge build landed on the right org/property and Clara can answer a couple of P0 questions from it. Proof: a pass/fail line posted to #updates-fede right after a build.

(e) Per-client Clara AppFolio login + wizard step

Reuses: D4 in section 8 (already recommended), Western Slope's own dedicated login as the template. Missing: the wizard step, and a Clara login for Situs separate from the JP&Co one it shares today. Proof: Situs has its own Clara user, added by the client, confirmed on their AppFolio account page.

From the mailbox audit (Western Slope, also needed for Situs) — owned by the shared-mailbox lane. See the go-live tracker row ws-shared-mailbox-access-gap-2026-09-15 (docs.propflowai.co/a/western-slope-go-live) and the design section docs.propflowai.co/a/email-architecture-2026-08-14#inbound-lead-flow-2026-09-15.

Proposed — pending Fede's review (2026-09-15)

Not now: Clara interviewing the team (long-term only, not this build); sending the questionnaire to the client fully automatically — that stays gated on Fede's check until two company runs have gone cleanly through hello@ first.

14 · Design: intake document → knowledge base (2026-09-15)

Proposed — pending Fede's review · 2026-09-15

Goal: a new client's answers about how they operate become the facts Clara speaks from, at the company level and per building, without anyone at PropFlow retyping them.

Inputs

  1. Raw AppFolio pull — units, listings, guest cards, work orders, lease templates/documents. Deterministic script; browser robot only where there is no API (Situs).
  2. Leasing mailbox audit — sources, notification pipes that are off, staff reply habits. Western Slope audit is the model.
  3. Off-system documents — lease form, fee schedule, application process, specials. The client uploads these into their knowledge base themselves; we do not take them by email (Fede, 2026-09-15: "we would want them to upload those into the knowledge base instead of sending them").
  4. The client's setup — one building or scattered homes under a company per Gera's model. Decides where each fact lands.
  5. The client's answers — confirm, correct, answer. From the questionnaire review.

Today: a customer-facing document upload already exists — the property page's Knowledge Upload modal (KnowledgeUploadModal.tsx) posts a PDF/text file to /api/properties/[id]/knowledge/ingest, which extracts discrete knowledge sections with an LLM and saves them to the property's DynamoDB knowledge row — so the upload step is existing, not to be designed, and the draft generator reads documents from that knowledge base store, not from a mailbox.

The core checklist comes first (Fede, 2026-09-15)

Proposed — pending Fede's review (2026-09-15)

Fede's ruling, in his words: asked whether the system should check coverage after the draft, he said "no i think we should know what we need before hand" and "obvious things like that… should just be part of the core checklist."

Meaning: a leasing knowledge base has a fixed list of must-haves, defined before any client is looked at. The pull fills what it can and marks each item found / conflicting / missing. The questionnaire is derived from the gaps and cannot skip a must-have. Done means every must-have is filled.

Why: Western Slope's 26-item review never asked for the application link, because no list existed. The review was built from what the data offered, not from what a prospect needs.

Core leasing checklist — Western Slope audit, 2026-09-15

Proposed — pending Fede's review (2026-09-15)

#Must-haveScopeStatus
1Office hourscompanyConflict (record Mon–Thu 9–4; client Tue–Thu 1–3 walk-ins; Friday contradicts itself)
2Phone, email, addresscompanyFilled
3Apply linklistingEmpty
4Application feecompany + exceptionsConflict (record $27, past charges $32, client $40; Courtyard/Lincoln $0 vs $40)
5Decision timecompanyFilled (1–2 business days)
6Who applies, ID + income documentscompanyFilled
7Income requirementcompanyFilled (~2x rent)
8Portable screening reportcompanyFilled
9Co-signerscompanyFilled
10Vouchers + affordable unitscompany + 2 buildingsPartly (restriction item answered with a fee)
11Security depositlistingFilled (per listing, refundable, 60 days)
12Pet rules + depositcompany + exceptionsFilled; 632 Hill exception held out (fair housing)
13Assistance animalscompanyFilled, overrides client wording
14Lease termscompany + Ember exceptionFilled (Ember 14–18 month promo)
15Month-to-month noticecompanyFilled (30 days, +$150)
16UtilitieslistingPer unit, not policy
17Renter's insurancecompanyFilled ($100k; $10.50 fallback)
18Smokingcompany + 2 exceptionsFilled
19Tour methodcompany + 2 exceptionsFilled
20Tour booking link/hourscompanyEmpty
21Move-in payment methodcompanyEmpty
22Key handoffcompany + 3 exceptionsFilled
23After-approval stepscompanyFilled
24Specials/concessionslistingEmpty as policy
25Parking/laundry/amenitieslistingListing fields
26What Clara hands to a personcompanyEmpty as a fact

Totals: 15 filled, 4 conflicting, 5 empty, 2 listing-only.

Flow

Pull + audit → candidate facts with source labels → 12–20 item draft in the Camellia shape (company policy vs building fact; internal-only and settings excluded) → hello@propflowai.co check → link + password to the client → answers → "I'm done" → apply: company policy to the company tier, building facts to that building, provenance (who/when), three hold-outs (fair-housing conflict, answer not matching its question, "depends per unit") → before/after summary with held-out list to hello@ → Clara's four readers (text, email, voice policy variable, mid-call lookup) pick it up on the next contact.

Implications

Decisions

DecisionOptionNotes
D5 · Corrections DECIDED 2026-09-15Never verbatim. Every client answer is read through one lens — Fede: 'should we say this to a prospect directly, or is this language a business-to-business explanation of how the policy works behind the scenes' — and split into up to three parts: (1) Say to prospects: the public fact in Clara's voice; (2) Clara knows, never says: operating context that shapes behaviour (what to steer toward, when to hand off, what not to promise); (3) Not knowledge: a question back to the client, or a setting. Prospect lens also applies to our own proposed text (Fede: "that should include Clara's own answers").
D6 · Re-apply vs staff editsA) RECOMMENDED — staff edits always win, the review is a seed, not a re-provisioning step.Staff own the live knowledge base. Re-apply is safe.
B) The review overwrites on every re-apply.Staff corrections get clobbered; re-apply becomes rare and defensive.
D7 · Company tier at a real clientA) RECOMMENDED — first write only after Fede reads the before/after summary on hello@.Prevents one wrong company answer from reaching every home on day one. Scales: second run goes straight in, diff posted to #updates-fede.
B) The hello@ check is enough, write immediately.Faster, but no backstop for an error that touches every property.

Example — Western Slope item 1, office hours

Jay's answer: "Our office is closed Monday and Friday. Tuesday–Friday 1–3pm our doors are open to the public, but we encourage prospects to call us instead to receive assistance. We also accept physical appointments."

Implications

State of the Western Slope record, 2026-09-15

Proposed — pending Fede's review (2026-09-15)

Not decided here: the generator prompt, the harness, the automatic trigger. No code until Fede settles the above.

Lessons for the automated pipeline

Proposed — pending Fede's review (2026-09-15)

Rules for the knowledge base writer (Fede, 2026-09-15, from the Western Slope pass)

Fede reviewed the first machine-drafted knowledge base for Western Slope entry by entry. Every rule below is a mistake the draft made. The script, the draft generator and the review page follow them from now on. Result: Western Slope knowledge base.

  1. The client's answer is the decision. Once the questionnaire is answered, the answer is the fact. Old charges, unit settings and lease templates are context in the internal note, never a "conflict" and never a question back. (Fee: Jay said $40 twice; the draft flagged it against $32 history.)
  2. Ask back only when the client's own answer contradicts itself, and even then take the explicit statement (Friday: "closed Monday and Friday" wins over "Tuesday to Friday 1 to 3").
  3. Entries are facts, not lines. Never write what Clara will say ("Tell me which home and I'll give you the amount", "I'll text you the link"). Write the fact; Clara phrases it per channel.
  4. Short. Figures as variables, no explanations. "Refundable pet deposit $300 total. Pet rent $35 per pet per month." A caller cannot follow a paragraph.
  5. Company table and property table, separate. The general rule lives at the company (a leasing associate hands over keys). The exception lives on the building it names (Pomona Park, Ember Estates, Flats on Elm: door code, keys inside). Never a company entry that lists building exceptions inline, and never a company entry whose only content is naming which buildings differ.
  6. Listing data is not knowledge. Rent, deposit amount, utilities included, promotions and the Apply link for a specific home come from the listing. The knowledge base holds only the rule ("deposit is usually one month's rent; amount on each listing").
  7. Never ask the client what the platform does or what the listing knows. No "how do prospects book a tour" (Clara books it), no "what is the apply link" (each listing's Apply button), no "what is the move-in payment method" unless a prospect actually asks that.
  8. Volunteer nothing sensitive. "No pets" is the entry for 632 Hill. Assistance animals are not mentioned; if asked, Clara's standing behaviour sends it to the leasing team. No "review with counsel" notes on a client page.
  9. No investor words. "Portfolio", "units", "screening report" only where the client uses them. "Home", "the office", "the leasing team".
  10. The review page is the cleaned version only. Two tables, property above company, columns # / topic / entry. No raw column, no banner, no questions section, no flags unless rule 2 applies.
  11. Three layers. Company = the general policy. Property = its exceptions only. Listing = what that home adds on top (rent, deposit amount, utilities, promotions). The writer never copies a listing fact into either table. (Fede, team meeting 2026-09-15: "general ones at the company, some exceptions at the property level, and the listing could specify something in addition.")
  12. Short because Clara reads it all. On a call she tends to read the whole entry. Anything per home or at the team's discretion is one line that ends in "on the listing" or "the leasing team decides", never a paragraph. (Fede, same meeting: "I don't want Clara to read all this on a phone call.")
  13. "How do people apply" is an action, not an entry. Check how the client's staff do it in their sent mail and guest cards before asking anyone. Western Slope: staff click "Send application" on the guest card in AppFolio; one form per home; no generic link. Clara has no per-home apply link today (one link per property setting); gap logged on the Western Slope page.
  14. Classify before writing. Each client answer is first sorted: prospect-facing fact, internal context Clara knows but never says, or not knowledge (listing data, setting, action). Never transcribe the raw answer. (Fede, 2026-09-15.)
  15. Tag the audience. Every entry carries who it is for: prospect, resident, staff. A resident-only fact never reaches a prospect. (Fede, 2026-08-26: "how do we segment the knowledge base so we don't give this info out to everyone.")
  16. The questionnaire triggers the build. No person writes or runs a script per client. Said in four sessions since 2026-09-02: "that works for one customer, it doesn't work for ten."

Mined 2026-09-15 from every session since August: five of the rules above had already been said before today (tiers 4 sessions, automation 4, short 3, trust the client's answer 3, listing data 2). Full hit list in the session scratchpad kb-corrections-history.md.

The test that keeps these rules alive: western-slope-knowledge-gold-set.json holds Jay's 26 raw answers and the 24 entries Fede approved. The first draft-generator PR must reproduce those entries from those answers (topic, tier, and every figure) before it merges; a rule without that check is just prose.

Verbosity budget still applies on top (Aug 29 knowledge-layer): voice one figure and one date per turn; text answer plus figure plus link; email full.

AppFolio: sending the rental application (documented 2026-09-15, not built)

Documented — not built (2026-09-15)

Ran the flow once, headless, at Willows (property 45, jpco.appfolio.com), to document it — not to automate it. Guest card action row: Rental Application ▾ → Send Rental Application (AppFolio's own help docs still call this "Email Rental Application" — the label changed). Opens a "Send Rental Application by Email" modal: Unit or Campaign (searchable, blank by default, not pre-filled from the guest card's existing interest), Recipients (pre-filled with the guest card's email), optional Bcc and SMS checkbox, and a pre-filled Message. Submits to POST /guest_cards/{id}/email_rental_application, confirmed by a 204 response and an "Email Rental Application Sent" line in the guest card's own audit log.

Matching the right property

Matches rule 12 above: no generic per-home apply link is exposed here either — AppFolio builds and sends it, and it never appears in the admin UI or any captured request.

16 · Go-live switches: two front doors, two switches (inspected 2026-09-16)

Built and merged 2026-09-16 — dry run pending

The rule Fede set today. A new client connects their mailbox, calendar and AppFolio and everything reads and records from that moment, with no flags. Two front doors bring people to Clara: the phone line and the leasing mailbox. Nobody gets Clara's text number any other way, so texting needs no gate. Voice goes live when the client forwards their number. Email goes live when we flip the company's live switch, which holds every email Clara would send for that company until then. That is the whole go-live: one flag on our side, one call-forward on theirs.

What exists today, per front door

Front doorTodayMatches the rule?
Email reading (mailbox connected)Push mailboxes read immediately at connect. Shared mailboxes that Microsoft refuses push on fall to the pull reader, which is behind two global switches: a disabled schedule and an environment flag. With those off the mailbox is never even classified as pull.Yes Western Slope's leasing mailbox is on the push (webhook) lane and is read today: 82 ingestions in the 3 days before 2026-09-16.
Email replyingThe company live switch exists (field on the company, set only through an admin API call, no button, on purpose). It holds two things: the first reply to a guest card from AppFolio or a listing site, and the follow-up cadence for those leads. A human who emails the mailbox directly, and a website lead arriving by email as a human message, are still answered while the company is not live. This is the narrow version kept after the 2026-09-11 revert of the "hold the whole inbox" PR.Partly The switch is the right one. Its reach is too narrow for today's rule.
VoiceNo live gate in our code. The line answers, books, texts confirmations. But a company's number is not something an operator connects: it must be added to a checked-in registry file in the repo and bound to a property by staff through the admin API. Neither Fairhaven nor Western Slope has a line attached through the company attachment model; Western Slope's front-door number is mapped by that registry file.Yes Wiring a number is an engineering onboarding step; not on the go-live path.
TextNo live gate. Cadence texts for guest-card leads are held only because the cadence itself is held by the live switch.Yes
CalendarCompany calendar connects with the mailbox in one consent and tours land on it. Booking on individual agents' calendars is a per-company setting, off by default.Yes for the company calendar.

The company's own settings blob at Western Slope also carries copies of the global email and SMS switches set to off. Nothing reads those copies; the real switches are global and on. Harmless, but confusing, and worth deleting in the same chain.

Other switches found, and why they do not matter here

PM reminders are opt-in

Fede, 2026-09-16 evening — in progress

Reminder emails to the property manager (e.g. "New application to review") are a per-company setting, off for everyone by default. Turning them on means naming the email that gets them. No new client gets reminders unless they opt in. Camellia (JP&Co) is opted in with its current recipients so nothing changes there. Origin: on 2026-09-16 the hourly reminder sent 100 emails to Western Slope's leasing inbox, one per open application imported at onboarding. The company live switch does not gate these (Fede rejected that).

The plan: four small dark PRs

  1. Reader always on. Delete the environment flag and the disabled-schedule arming step from the pull reader. The reader runs every minute and reads every pull-mode mailbox. Safe by construction today because it only hands over replies on threads Clara started, and it stays that way until the lead-source setting widens it.
  2. Live switch becomes the master email gate. Move the check from the two narrow seams to the outbound email seam itself, keyed by company: any email Clara would send on a company's behalf to a prospect, tenant or applicant is held and ledgered with reason "company not live" while the switch is off. Inbound is still read, recorded, classified and threaded, so the day the switch flips, nothing is lost.
  3. Show the switch. A "Clara replies to email" line on the company page with its state and date, and the switch itself, staff-only. Today the card only appears once live and there is no button.
  4. Phone line as an attachment, not a repo file. Attach a number to a company through the admin page using the phone-line attachment model that already exists, and generate the registry from it. This is the largest item and can trail the other three; Western Slope's line already works through the file.

Each PR ships dark, is proven on Fairhaven (sandbox tenant) and Willows, and flipping Western Slope live stays Fede's press. All merged 2026-09-16 (page switch #8889, Zillow suppress #8896, gate #8893, reader #8888); the email gate covers every customer-facing door: the two send seams, the inbound Lambda, the prospect-touch door used by tours and follow-ups, and vendor dispatch. Team mail is never held. Reader proven in prod 22:32Z (schedule on from config, poller ticking, Western Slope stamped push). Gate dry run at Fairhaven pending a neutral-domain prospect inbox.

Decisions

QuestionOptionsRecommendation
D0. What the switch holds DECIDED 2026-09-16(A) Everything customer-facing: no email leaves Clara for a dark company. (B) Portfolio-arrived leads only (as built). (C) B plus website form leads.A, chosen by Fede. The client's staff still answer their own inbox as before, so no prospect goes unanswered; Clara reads, records and sends nothing. To try the email door before go-live, flip the switch for the test or use the phone door.
D1. Does the master email gate also hold Clara's emails to the client's own team (escalation forwards, PM reminders, owner reports)?(a) Hold everything Clara emails for that company. (b) Hold only prospect, applicant and tenant email; team notices still go.(b). The client testing their own line should see every notice, per the 2026-09-13 rule. The risk being guarded is a stranger getting a reply, not staff.
D2. Auto-replies from the mailbox itself (out-of-office style acknowledgements), if any: held too?(a) Held. (b) Allowed.(a). "No outbound comms from Clara until turned on" reads as all of it.
D3 · PM reminders opt-in DECIDED 2026-09-16(a) Off by default per company, opt-in names the recipient email. (b) On by default for every company.(a). Camellia (JP&Co) opted in with its current recipients; no new client gets reminders unless they opt in. See "PM reminders are opt-in" above.

Evidence: production reads of both companies' profiles and attachments (2026-09-16); code paths company-mailbox-poll-flag, org-mailbox-inbound, inquiry-outbound-hold, outreach-trigger, the inbound-processor send gate, clara-live admin route, phone-lookup and phone-registry. Full file list in the session notes.

17 · Hours: one canonical store, not knowledge prose (2026-09-18)

Diagnosis + design rule — follow-up to the 2026-09-17 Western Slope weekend-tour incident (go-live audit, section 11b)

Diagnosis

Hours ended up in five places, three values, because nothing writes hours in one spot. tourHours and officeHours (both structured) are set by staff scripts. Separately, the 09-15 knowledge pass hand-typed a sentence off the client's website into a knowledge entry ("Closed weekends and holidays.") and got it approved into the gold set — nothing compares that sentence to the setting that already existed. Two independent writers, same fact, never reconciled; only a live call surfaced the disagreement.

Design rule going forward

Build-time check (idea, not built)

Fail the knowledge-base build/apply step when an entry's text contains hour-like patterns (day names, time ranges, "closed", "by appointment") for a field with a structured setting on the same org/property — same shape as the provisioning-script guard already added for officeHours (#9188/#9214), generalized to knowledge prose and to tourHours. Not built; named as the open item on the go-live audit.

Sources

~/situs-data/onboarding/PLAYBOOK-AUDIT.md (forensic audit, timeline, playbook v1, entity inventory, missing documents, repo options) · ~/situs-data/onboarding/UX-RESEARCH.md (patterns, principles, UX spec, wireframes, voice mapping) · ~/situs-data/analysis/CAMELLIA-ASSUMPTIONS-AUDIT.md (go-live blockers) · ~/situs-data/analysis/POLICY-LEDGER.md · ~/situs-data/analysis/replay/RESULTS.md, RESULTS-KB.md (run 2) · ~/situs-data/onboarding/question-bank/ (README.md, question_bank.csv, fact_keys.csv, coverage.csv, coverage_fill_list.csv, RESEARCH.md) · ~/situs-data/analysis/memo-corpus-for-clara.md · ~/situs-data/analysis/WINDOW-AUDIT.md · ~/situs-data/STATUS.md, FLEET-BRIEF-2026.md, situs-dump-2025/RUN-LOG.md, the run manifests · ~/.claude/propflow-vision-2026-08.txt · Situs Group initiative hub · Situs Group — What the Records Show (2026)

PropFlow Docs