Decision page · 2026-09-08 · for Gera and Fede · research at propflowai@d0bed136d3

Settings placement: criteria, inventory and the five decisions

Update, 2026-09-17: Property.emailShadowMode, Property.smsShadowMode and scripts/set-property-sms-shadow-mode.ts, listed below as existing knobs, were deleted by PR #9162 — read every mention of them on this page as history, not current fields. Staff notices now always reach the real recipient and tour texts are always sent, with no per-property shadow gate.

The settings pages are "pretty vanilla" (Gera) and the product is about to grow policies, rules, prompts, flags and deciders. The open question with Fede is where each of those lives: one of the four settings levels, the property detail page, or inside a module. Two read-only sweeps of the codebase at d0bed136d3 (after the four-level split, #7324 and #7326) produced this page: an inventory of every knob that exists today and where it is, and a set of placement criteria applied to about 95 current and proposed knobs. The short version is that the codebase already contains most of the answer, and that a good part of what exists is stored at the wrong level.

What each page would look like

Wireframes of the recommendation, each with a dropdown for the choice underneath it. Field names are the real knobs from the inventory below; the values are illustrative sample data, not any account’s real configuration.

from company inheritedSet here property overrideread-only shown, not editable here

First, the gap: three places already hold building configuration

Before choosing where anything should go, this is where it is now. All three of these are live today.

Settings › Property/settings, with a property picked
  • Integrations
  • Calls
  • Leasing & tours
  • Emails & reminders
  • Maintenance Automation — incl. the auto-approve ceiling
The Property page/properties/<id> — what you get when you click a building
  • Property details (phone, website)
  • Pricing & fees
  • Renewal policy — incl. “Autonomously send renewal offers”
  • Turnover policy
  • Knowledge & concessions
The module pagesLeasing, Maintenance, Renewals, Collections
  • Follow-up cadences
  • Preferred vendors by trade
  • Chase cadences
  • Qualification rules
The gap, in one line. Maintenance autonomy is in Settings. Renewal autonomy is on the Property page, under “Eligibility & autonomy”. They are the same kind of decision — how far Clara may go on this building — and they live in two different places for no reason anyone chose. That is what makes “where does this go?” genuinely hard to answer today.
recommended
Settings › PropertyCamellia House ⌄
Autonomy
Off
Suggest
Act with approvalcustomer ceiling
Autonomous 🔒
One ladder per module: Leasing, Maintenance, Renewals, Collections. The only writer.
Renewals
Max increasefrom company8%
Open windowfrom company90 days before end
Also call the tenant
The renewal policy numbers move here too, next to the rung that governs them.
Every “how far may Clara go” answer for this building, in one place.
Property pageCamellia House
This building
Address1200 Larimer St
Units48
Occupancy80.4%
Open work orders37
Clara here
Clara here: Act with approvalread-only · opens Settings
A pill linking to Settings, not a control.
The building page goes back to being about the building: what it is, how it is doing, who lives there.
Recommended. One rule to remember: if it decides what Clara does, it is in Settings; if it describes the building, it is on the building page. Pricing, knowledge and concessions describe the building, so they stay put.

1 · Account — you

Account Settings
Profile
Photo◍ uploaded
NameDana Whitfield
Emaildana@propflowai.co
Phone(303) 555-0142
RoleProperty Manager
Time zone shown to meEach property’s clock
Notifications
DeliveryOne daily digest
PM action reminders
Weekly owner report copy
Mine alone. Nothing here changes what a resident or owner sees.
Security
Two-factor required by companyAuthenticator app
Passkeys1 registered
Active sessions3 devices
One person, one page. Company Name moves off this page — it sits on the user row today and belongs to the organization.
recommended
Account Settings
Profile
Photo◍ uploaded
NameDana Whitfield
Emaildana@propflowai.co
Phone(303) 555-0142
RoleProperty Manager
How I want to be told
DeliveryOne daily digest
Action reminders
Weekly owner report copy
Only ever about me. Does not exist today — “Reminders for you” currently sits on Property Settings, per building. Distinct from Property › Notifications, which is who gets told.
Set by my company
Two-factor company policyAuthenticator app
Reminder cadence capped by companyat most 1 / day
Only company rules that constrain me personally: one I must act on (enrol in 2FA) and one that caps a setting of my own. Resident quiet hours are not here — they govern what residents receive, not what I do, so they never appear on a personal page.
A clean line: my delivery preferences are mine; anything a resident feels belongs to the company or the building.
Recommended. The test that decides it: can this setting change what a resident experiences? If yes it is not personal, however convenient it would be to put it here.

2 · Organization — your company

Organization Settings
Company
Name Clara signs asCamellia Residential
Billing address1200 Larimer St, Denver
Logo◧ camellia-mark.svg
The name currently lives on your own user row. This is the fix.
What Clara may do
LanguagesEnglish, Spanish
Text messages
Email replies
Vendor quote & dispatch emails
Capabilities, not autonomy. A property may narrow these, never widen them.
Contact policy
Resident quiet hours9:00 PM – 8:00 AM
Contact ceiling4 per resident / week
After-hours emergencyWater, heat, gas, lock-out
Team
Members12 people · 3 admins
Assigned propertiesPer person
Shipped 2026-09-08 (PR #7339).
Integrations
PMSAppFolio · connected
Subdomaincamellia.appfolio.com
Hidden from sync3 properties
Hide-from-sync is a per-user list today. It is a company fact.
Defaults every property inherits
Follow-up cadencesset at org5 cadences
Preferred vendorsset at org14 by trade
Renewal chaseset at org90 / 60 / 30 days
Toneset at orgFriendly
Edited on the module pages; shown here so the company default is findable in one place.
Nineteen knobs. Nothing at this level is editable today — the organization writer is the first thing that has to be built.
recommended
Organization Settings
Contact policy
Resident quiet hours9:00 PM – 8:00 AM
Contact ceiling4 / resident / week
ToneFriendly
The company default. Set once.
Set here, applies everywhere unless a building says otherwise.
Property SettingsCamellia House ⌄
Contact policy
Resident quiet hoursfrom company9:00 PM – 8:00 AM
Contact ceilingSet here2 / resident / week
Tone from companyFriendly
Clearing a field returns it to the company value.
This building is stricter on contact frequency; the rest follows the company.
Recommended. This is Q2 on the page. Absence means inherit, and each row shows which it is, so onboarding a new building is mostly leaving fields alone.

3 · Property — one building

Property SettingsCamellia House ⌄
Autonomy · Leasing
Off. Clara reads, never writes.
Suggest. Clara drafts, a person sends.
Act with approval.customer ceiling
Autonomous. 🔒 PropFlow staff only.
One card, one row per module. Thirteen scattered switches collapse into this; each module page shows the rung read-only.
Clara at this property
Greeting line“Thanks for calling Camellia House”
Quiet hoursfrom company9:00 PM – 8:00 AM
Hand-off modeCoworker
Auto-reply on text
Calls
Transfer destinationSet here(303) 555-0180
Emergency phoneSet here(303) 555-0191
Business hours on property pageMon–Fri 9–6
Holiday closuresfrom company11 federal
Your example: the phone transfer destination.
Leasing
Tour durationSet here30 minutes
Minimum lead timefrom company2 hours
Buffer between toursfrom company15 minutes
Application linkSet hereapply.camelliahouse.com
Post-tour follow-up from company2 hours · text
Your other two examples: tour duration and the app link.
Notifications
Escalation ownerSet heredana@propflowai.co
Maintenance techSet here(303) 555-0164
Renewal contactfrom companyleasing@propflowai.co
Weekly owner report from companyMondays 8 AM
8 fields.
Integrations
Clara’s name at the PMSfrom companyCamellia Leasing
Clara’s numbers read-only(303) 555-0100
Delivery pathDirect
Property inboxSet herecamellia@propflowai.co
8 fields.
Fifty-one knobs, the biggest level. Every row says where its value came from: from company is inherited, Set here is a property override. Clearing a field returns it to the company value.

4 · Admin — PropFlow staff

Admin SettingsPropFlow staff only
Autonomy arms
Autonomous sending
Holdover conversion
Halt brake
Human approval before every send
The rung customers cannot reach.
Platform
Twilio provisioning4 numbers pooled
Workflow dispatch allowlist2 workflows
Topic labelling & grading
Ops channel for holds#alerts
Access
Role → tab permissions9 roles
Impersonation auditLast 14 days
Test-property flag
Fourteen knobs. Internal switches and the arms above the customer ceiling. Clara’s persona and after-hours behaviour stay in code, deliberately.

The end state: every level, every card, every field

2026-09-08. Gera: “We want the end state of this product — everything exactly as it should look, even if the logic isn’t connected. Unbuilt features greyed out with an ⓘ saying coming soon.” Six domain passes (identity & channels · leasing & tours · maintenance, vendors & turnover · renewals & collections · people, team & notifications · autonomy, compliance & admin), each grounded in the codebase, merged by level. Every field is marked exists or coming soon. Hover a row for the one-line reason and the code it points at.

Every greyed row now names the phase that un-greys it. Hover any coming soon row: after its reason it says — un-grays at P3 · rows in the dark, and so on. The phase ids are the architecture effort’s own (portfolio-architecture-how, phases P0–P9, 83–121 engineer-days from 2026-09-15), taken verbatim rather than minted here, so a phase landing is a diff on both pages. The keying rule is theirs: a row belongs to the earliest phase that makes its value expressible. It is assigned per CARD, not per field — 61 judgements rather than 265 — because a card is a coherent unit and a per-field guess would be false precision. Where a field in a card genuinely lands later than its card, the row’s own reason says so and the phase is the floor, not the promise. Five rows no phase un-greys, all in Admin › Coming-soon governance plus one module strip: that card is the settings registry that generates these pages, and no architecture phase builds it. Reported as a hole in the plan rather than papered over.
Two ladders, and they are not in conflict. This page’s levels are where a value is WRITTEN and by whom; the architecture’s (platform → customer → group → building → unit/person) is where a value RESOLVES. Same mechanism from two ends, agreed in those words with the architecture effort on 2026-09-08. Two consequences worth stating: Account is a person’s own surface and sits outside the resolution ladder entirely, and unit/person is a resolution leaf with no settings surface here. A group is a real rung on both (row 22) — but the set of buildings a phone number reaches is a label, not a rung: a building can sit behind two numbers, so letting a number’s reach carry policy would force a precedence nobody authored. If “everything on this number gets this policy” is ever wanted, that is a new decision, not an inference.
63 cards · 413 fields · 278 coming soon. Values are illustrative sample data. Field names are the product’s; the greyed rows are the design, not the build. The single gate under all of it: there is no organization writer today, so every “from company” badge below is intent, not state, until it lands.

Where is it decided? The shared-resource binding model

Your calendar and phone-number questions are the same question. A shared resource is provisioned at one level, owned at another, bound at a third, and sometimes personal. Today the four resources landed at four different scopes by accident; this is the deliberate model.

Decided 2026-09-08 (Gera, on the decisions page): the “Bound at” column below is the default picture, not a rule. Any shared resource may bind to one building, to a group of buildings, or to the whole company, and one customer mixes all three — his example: one number serves buildings one to three, buildings four and five have their own; a calendar can be company-only, shared by some buildings, or one per building. The settings page follows the nav: a building selected shows that building’s binding and where it came from; no building selected shows the company’s pool and every binding on it. This is the portfolio-architecture record’s model exactly: a doorbell hangs on a building, a group or the company; one resolver walks building → group → company → registry default; no mode. Every “Bound at: Building” row reads as “building, group or company”.
ResourceProvisioned byOwned atBound atPersonal?Shown whereToday
Phone number (voice + text, same line)PropFlow staff (Twilio)Company — the number poolBuilding — one or more per buildingnoOrg › Phone numbers (pool) · Property › Lines & inboxes (picker)Property.twilioNumbers is absent everywhere; an env map; each new number is a source PR
Company main linePropFlow staffCompanyCompany routing tablenoOrg › Phone numbers › Main lineDoes not exist; called-number → building is the only resolver
Email inbox Clara readsCustomer (OAuth)Company tenant consent (coming soon)Building — one mailbox eachno (shared team box)Property › Lines & inboxes · Org › EmailProperty.emailIntegration, authorised per building
Sender identity (from-name, address, signature)CustomerCompany default (brand + domain)Building overridenoOrg › Clara's identity · Property › Send email asPer-property script-only; global clara@propflowai.co fallback
Delivery path (direct vs through the PMS)Company (a property of the PMS account)BuildingnoOrg › PMS · Property (badged)Per-property only today
PMS account (credentials, database)Customer enters; staff rotateCompany — may hold several databasesBuilding — which database + Clara's seatnoOrg › PMS accounts · Property (read-only)Credentials keyed PER USER today (PMSCRED#<userId>)
Tour calendarCustomer (OAuth)The person, or a shared mailboxBuilding picks from the offered listYESAccount › My calendar · Property › Tours › Book tours onOnly a per-building Outlook connection is read (Property.leasingCalendar); the person-level connection exists but is never read for tours
Voice agentPropFlow staffPropFlowBuilding, via the called numbernoAdmin › Voice agents · Property (read-only)Agent ids are code constants
Timezone · website · listings feeda fact about the buildingnoBuilding pageTimezone has NO writer at all — quiet-hours gating defaults to Chicago
Language Clara answers inCompany capabilityBuilding overrideperson preference on the spineOrg › Clara's identity · Property rowNo company or building knob; a per-person preference only

Two corrections from the identity pass, both verified: the tour calendar is read from a per-building Outlook connection today (the person-level one is written but never read), and PMS credentials are keyed per user, not per company — the same misfile as company name. One bug the pass reported was already gone by the time this published: onboarding used to show every new customer the literal +1 (844) 510-1007 — one customer’s line — as “their” number; #7304 removed it the same morning and a test now forbids any phone number on that step. The other bug from this pass, the global text/email switches writable by any role, is closed by #7365 (staff-only on write).

The Autonomy ladder, row by row

One shared enum, the same four words on every row. The rung is a projection over fields that already exist — no new column per row. Customers stop at Act with approval; Autonomous is unlocked per building by PropFlow after a soak.

ModuleOffSuggestAct with approval (customer ceiling)Autonomous (staff only)
LeasingcapabilityStage.leasing='off''shadow' + drafts (soon)newLeasePipelineEnabled, lease send stops at draftautonomousLeaseSendingEnabled + autonomousListingPublishEnabled
Tourslane off (soon)propose only, PM confirms (PROPOSED)escalatedTourBookingEnabled=falseescalatedTourBookingEnabled + tourRequestSmsEnabled
MaintenancecapabilityStage.maintenance='off''shadow'dispatch held (autonomousVendorDispatchEnabled=false)autonomousVendorDispatchEnabled + autonomousTurnoverEnabled, inside the spend limit
RenewalscapabilityStage.renewals='off''shadow' + draftsautonomousRenewalEnabled=false ("every renewal pauses for review")autonomousRenewalEnabled + autonomousHoldoverEnabled
Collectionsnot enrolleddraft dun shownFIXED here by ADR-0125not offered — ⓘ "always needs a person's approval"
Conversationsgreyed — Clara always answersgreyedhandoffMode='coworker' (park and hold)handoffMode='autonomous' (answer, say so once, move on)

The ceiling model. Platform ceiling (PropFlow staff, per company × row) → company cap (org admin, also carries the default for new buildings) → building value (PM). Every row badges its source. Rungs above the cap render greyed with ⓘ “Capped at Act with approval by Camellia Admin”. Under the ladder sits the one spend line: Clara may approve up to $500 per job without asking, with turnovers as a sub-line. Shadow / live / test shows as a chip from Admin-owned state, never a control.

Ceilings versus defaults

The difference between a value a parent locks and one it merely pre-fills is the difference between a compliance posture and a suggestion.

SettingPlatform ceiling?Company may setBuilding may setWhy
Autonomy rung, per moduleYes — max Act with approval until staff raise it per buildinga cap ≤ ceiling, and a defaulta value ≤ org capArt. IV.6: activation is Fede's, every time
Collections rungYes — fixed at Act with approvallower onlylower onlyADR-0125
Spend Clara may approveYes — a maximum dollar figure (founder number)a default ≤ ceilinga value ≤ org defaultMoney leaves the customer's account
Channels (SMS, email, voice)Yes — plan gates them onon / offoff onlyNarrow-only
LanguagesYes — platform listsubsetsubsetClara can't speak what she isn't tested in
ModulesYes — plannone (read-only)noneWhat the plan buys
Contact ceilingYes — a platform maximum nobody may exceeda lower numbernoneCompliance posture; today org-only with no platform floor
Quiet hoursYes — 8 PM–9 AM is the widest anyone getsnonenarrower onlyTCPA floor
Opt-out honouring · fair-housing railsFixednonenoneLaw / never a switch
Emergency definitionsYes — platform baseline (gas, fire, flood, no heat)add onlyadd onlyLife safety cannot be unchecked
Record retentionYes — floors per record typelonger onlynoneKeep more, never less
ToneYes — the evaluated setpickpickPrompts are code
Brand, company name, notification recipientsNo ceilingdefaultoverridePure defaults
Test / shadow / live, kill switches, arms, allowlistsStaff only — not on the chainnonenoneObservability and cutover state

The pages

1 · Account — you

Only what constrains me personally. Company policies appear here only when I have to act on them.

30 fields across 6 cards · 5 exist today · 25 coming soon

Account Settings
Profile 5 fields · 2 coming soon
Photo◍ uploaded
Name · Email · PhoneDana Whitfield · dana@propflowai.co · (303) 555-0142
Time zone shown to meEach property's clock
Language (my UI)iEnglish
My role and propertiesiProperty Manager · 3 buildings → Team
How I want to be told 12 fields · 11 coming soon
Page me on emergencies at my buildingsi
Daily maintenance digesti8:00 AM
Include vendor no-response chases in my digesti
Renewals waiting on meiDaily digest
Collections replies and holdsiEach
Reminders about my to-dosicapped by companyon · up to 3 · every 24h
Delivery for FYIsiDaily digest
Delivery for asks addressed to my roleiAlways each
Channel per kindiEmail + text for asks
Don't page me betweeni10 PM – 7 AM (my clock)
Life-safety pagesAlways, all hours
Out of office / who covers for meiSep 12–19 · Marcus
Does not exist today (knob 78). Distinct from Property › Notifications, which is who gets told.
My calendar 4 fields · 4 coming soon
Connected calendariOutlook · dana@propflowai.co
Offer this calendar to my propertiesi
Buildings booking on my calendariCamellia House, Elm St
Hours Clara may book meiMon–Fri 9–5
It is your calendar; tours land on it. Today only a per-building Outlook connection is read (Property.leasingCalendar, types.ts:3060).
My showing calendar & availability 4 fields · 4 coming soon
Hours I take toursiTue–Sat 10–5
Max tours per dayi6
Days offiSun, Mon
Tell me when a tour lands / moves / no-showsiText me
Nothing per-agent exists today; one property calendar serves every agent.
My connections 2 fields · 2 coming soon
Outlook / Google calendar + inboxiOutlook · connected
Phone for SMS pagesi(303) 555-0142 · verified
Security 3 fields · 2 coming soon
Two-factorirequired by companyAuthenticator app
Active sessionsi3 devices · sign out everywhere
Sign-in methodGoogle

2 · Organization — your company

The defaults level: every inherited row is authored here and merely overridden per building. Nothing here is writable today.

177 fields across 21 cards · 47 exist today · 130 coming soon

Organization Settings
Clara's identity 10 fields · 7 coming soon
Company name Clara signs asCamellia Residential
Clara's nameClara
Sender display nameiClara at Camellia Residential
Default from-addressiclara@camelliares.com · Verified ✓
Email signaturei— Clara, Camellia Residential
Logo / brand colouri◧ camellia-mark.svg · #1D4ED8
ToneiWarm
Languages Clara answers iniEnglish, Spanish
Voice greeting"Thanks for calling Camellia House, this is Clara…"
How to pronounce the company nameika-MEEL-ya
Phone numbers 6 fields · 5 coming soon
Number pooli4 numbers · 1 on the company · 1 on a group of 3 · 1 on one building · 1 unassigned
Request a numberiRequest →
Company main lineiNone — each building has its own
Caller-ID nameiCamellia Residential
Text consent modeliSingle opt-in
Team test phones2 numbers
One number per building, voice and text on the same line, auto-assigned from this pool at onboarding. Called-number → building is the only deterministic routing the system has.
Email 4 fields · 4 coming soon
Workspace connectioniMicrosoft 365 · not connected
Sending domainicamelliares.com · Verified ✓
Read-but-don't-answer senders (default)inoreply@appfolio.com, +2
Team reads the inbox (default)i
Property management system 9 fields · 5 coming soon
Accountscamellia.appfolio.com · 38 buildings
Add account / Rotate / DisconnectRotate credentials
Clara's seat per accounticlara.leasing · "Camellia Leasing"
Delivery path (default)iDirect
Hidden from sync3 buildings
Messaging import per accounti
Vendor job referenceiWork order
Who owns visit schedulingiPropFlow
Vendors come fromAppFolio (synced)
Team 9 fields · 6 coming soon
Members12 people · 3 admins
Invite (name, email, role)Invite →
Assigned properties per personper person
Pending invites · resend / revokei2
Deactivate vs removeichoice
Regions (group buildings → regional manager)iDenver · Front Range · Mountain
Roles explained in plain EnglishiWhat each role can see and do
Seatsi12 (unlimited)
SSO / domain sign-iniNot connected
Who can manage people 7 fields · 4 coming soon
The writermanage-teammate.ts
Peers may edit each otherAlready true
Never the last adminAlready true
Who may manage peopleiorg_admin · + 2 delegates
Grant “manage people” toiDana R. (Property manager)
No escalationiEnforced
At least one holderiAlways
Three of these are shipped and read Already true on purpose — a design page that redraws working behaviour as “coming soon” gets it built twice. The four greyed rows EXTEND manage-teammate.ts; they are not a second writer beside it.
Notification defaults 10 fields · 9 coming soon
Renewals needing reviewi{Property manager}
Lease signed / rolled to month-to-month{Accounting}
Legal-stage escalationi{Escalation owner}
Weekly owner reporti{Owner contacts} · PM inbox always copied
Default recipient per eventiEvent catalogue below
Accounting inbox / lease-signed CCi{Accounting}
Owner report cadenceiWeekly
Staff reminders allowed + max cadenceion · at most 1 / day
Digests on/off (stale leads, sync, leases-ending)ion · on · off
Team chat destination (Slack / Teams)iNot connected
Escalation policy 7 fields · 5 coming soon
Ask again everyi24 hours
Stop asking afteri3 reminders
Then move up toi{Regional manager} → {Org admin}
Only during office hoursAlways
After-hours: who is on calliWeekday: Dana · Weekend: Marcus
What counts as an emergencycompany list
How much the office hearsiEverything
Security policy 3 fields · 2 coming soon
Require two-factor for everyonei
Session lengthi30 days
Who may inviteRank table
Follow-ups 10 fields · 3 coming soon
Inquiry — never replied3 touches · 1d / 3d / 7d
Replied, then went dark2 touches
Tour proposed, never confirmed2 touches (capped at the 7-day hold)
Confirmed tour remindersi24h, 1h
Toured, never appliedApp link at +1h, then 3 chases
Lost-lead re-engagei30 / 60 / 90 days
Contact ceiling4 per prospect / week
Renewal offer — no responsei+2d, +9d · then 30d / 15d before lease end
Past-due balance21 / 28 / 31 days
Contact ceiling — collections lane3 / calendar month
Leasing standards 16 fields · 14 coming soon
Standard tour lengthi30 minutes
Minimum notice before a touri2 hours
Gap between back-to-back toursi15 minutes
Tour formats the company offersiIn-person, Virtual
Application portal linkiapply.camelliares.com
Company rental criteriai3× income · 620 credit · no evictions 5y
Standard fees (application / admin / holding deposit)i$50 · $150 · $300
Lease terms offered + defaulti6, 12, 15 · default 12
Clara may quote exact renti
Clara may quote fees & depositsi
Clara may quote current specialsi
Clara may state rental criteria (never evaluate)i
Clara may tell a verified applicant their statusi
Clara may send the application linki
After-hours prospectsAnswered 24/7; tours only inside open hours
Fair-housing guardrailsAlways on
Nothing leasing-shaped exists at Organization today; the resolver header says "No global fallback. Operational settings live per-property only." (settings-resolver.ts:4-5).
Maintenance policy 11 fields · 11 coming soon
What counts as an emergencyiNo heat, no water, flooding, lock-out, +3
Never handled without a personiCharge disputes, safety hazards
Response targets by priorityiEmergency 1h/24h · High 4h/3d · …
Self-serve troubleshootingion · skip for electrical
Ask the resident for a photoiOnce, then file
Ask for permission to enteriWhen the resident won't be home
Ask about pets on premisesi
Work-order categoriesi9 categories
Resident status updatesiMilestones only
Ask "was it fixed?" after closei
Visit windows Clara may offeri8–12, 12–4 · evenings off
Dispatch & spend 4 fields · 3 coming soon
Default autonomous-spend ceilingi$500
In-house firsti
Quotes required abovei$1,500 · 2 quotes
Use the go-to list without askingGoverned by each building's Autonomy rung
Vendor standards 8 fields · 6 coming soon
Certificate of insurance requiredi
When a COI is expirediWarn me
License required for tradesiElectrical, Plumbing, HVAC, Gas
W-9 / 1099 on file before first jobi
How Clara reaches vendors by defaultiEmail
Vendor language defaultiFollow the vendor's record
Chase cadencesSee Follow-ups
Vendor ratesLive on each vendor's record
Turnover standards 9 fields · 7 coming soon
Inspect the uniti1 day after move-out · 10:00 · 60 min
Unit ready withini7 days
Default trades on every turniPaint, Clean, Carpet
Finishing trades (run last)iHousekeeping
Task type libraryi14 types
Make-ready checklisti6 rooms · 31 items
Key handling on move-outiLockbox · rekey every turn
Turnover dispatch cost capSub-line of the Autonomy spend ceiling
Move-out charge conventionsMined per building — see the building page
Preventive maintenance 3 fields · 3 coming soon
Recurring schedulesiHVAC filters q3mo · dryer vents q12mo · +2
Seasonal remindersiWinterize, AC pre-season
Warranty check before dispatchi
Renewals — company standard 19 fields · 14 coming soon
Open the renewali90 days before lease end
Rent strategyiMinimum increase
Minimum increasei3 %
Maximum increasei8 %
Term options offeredi6, 12, 15, 18
Pricing by termi6-mo +$75 · 18-mo −$25
Month-to-month premiumi$150 / mo
Offer expiresi30 days before lease end
Concessions Clara may mention on renewaliNone
Eligibility: max unpaid renti2 months
Eligibility: max late payments (12 mo)i2
Eligibility: days after the 1st before a payment counts latei10
Eligibility: open lease violationsiAny → review
Ineligible residentsGo to your review queue
Negotiation: Clara may accept a lower renti0 % (never)
Negotiation: switching termOnly among the terms in the offer
Negotiation: anything elseHands to the property manager
Lease executionSent for e-signature through AppFolio
Change reason required when policy changeson
Collections — company standard 11 fields · 9 coming soon
Start chasing when balance is at leasti1 month · $50
Don't re-chase the same resident withini30 days
ToneiPlain
Payment plans: what Clara may agree toiNever
Hardship or assistance mentionedReminders pause; PM is told; case moves to Assistance applied
Legal handoff: wheniManual only
Legal handoff: to whomi{Eviction counsel} — a vendor, trade legal
Demand letters: who signs as agenti{Property manager}
Owner reporting: include past-due sectioni
Owner reporting: windowiWeekly
Owner is told whenFlagged for eviction
Compliance 10 fields · 6 coming soon
Contact ceilingNo more than 4 touches / person / week
Quiet hours8 PM – 9 AM on the building's clock
Opt-out handlingSTOP honoured on every channel, forever, across all buildings
Where opt-out notices goi{Property manager}
Emergency definitionsicompany list (gas, fire, flood locked)
Fair-housing railsAlways on
Record retentioniconversations 7y · consent ≥4y · audit 7y
Data exportiRequest export →
Deletion requestsiRequest erasure for a person →
Activity logiWho changed which setting, who approved what
Rules Clara follows for every resident in the company.
Plan & billing 5 fields · 3 coming soon
PlaniPro
Units billed412
SeatsUnlimited — pay per unit
Usage this monthi2,140 texts · 318 calls · 41h
Invoices & payment methodiStripe portal →
Clara's capabilities 7 fields · 3 coming soon
Text messages
Email replies
Phone calls (voice)i
Vendor quote requests by email
Vendor dispatch confirmations by email
Languages Clara answers iniEnglish, Spanish
Modules turned oniLeasing · Tours · Maintenance · Renewals · Collections · Conversations
What Clara is allowed to do at all. Buildings can turn these off, never on. Narrow-only is the rule.
Company autonomy caps 6 fields · 5 coming soon
Leasing — highest rung any building may pickiAct with approval
Maintenance — capiAct with approval
Renewals — capiAct with approval
Collections — capAct with approval (fixed by ADR-0125)
Default rung for new buildingsiSuggest
Default spend Clara may approvei$500
Platform ceiling → company cap → building value. Rungs above the cap render greyed with ⓘ "Capped by …". If a cap is lowered below a live building, the building clamps with a dated badge — the cap wins.

3 · Property — one building

Instructions to the software for this building. Every row badges where its value came from.

76 fields across 10 cards · 24 exist today · 52 coming soon

Property SettingsCamellia House ⌄
Autonomy 9 fields · 7 coming soon
Leasingifrom companyAct with approval
Toursifrom companyAct with approval
MaintenanceiAct with approval
RenewalsiAct with approval
CollectionsiAct with approval
Conversations (answering, hand-off)ifrom companyAct with approval
Clara may commit up tofrom company$500
— also for turnoverssame
StatusiLive since 3 Sep · turned on by Fede
One dial per job. Rungs above the company cap are greyed: ⓘ "Capped at Act with approval by Camellia Admin". Autonomous is PropFlow-staff only, everywhere.
Lines & inboxes 16 fields · 9 coming soon
Clara's number(s) for this buildingi(303) 555-0100 · shared with Elm St, Oak Ave
Office phone (transfer destination)Set here(303) 555-0180
Emergency phoneSet here(303) 555-0191
Inbox Clara readscamellia@camelliares.com · Outlook
Addresses this building ownsicamellia@…, leasing-camellia@…
Send email asifrom companyClara at Camellia House · Verified ✓
Team reads this inboxifrom company
Read-but-don't-answer sendersifrom companycompany list + 1
Delivery pathfrom companyDirect
PMS account this building lives inicamellia.appfolio.com
Clara's display name at this PMSfrom companyCamellia Leasing
Text consent modelifrom companySingle opt-in
Languagesifrom companyEnglish, Spanish
Voice greeting"Thanks for calling Camellia House…"
Public listings pageicamelliahouse.com/availability
Listing syndication targetsifrom companyInternet, Website
Renamed from "Integrations". What remains here is bindings — which number, which inbox, which PMS account — most of them read-only.
Tours 1 fields · 1 coming soon
Book tours oniDana's calendar (offered) · Leasing office (shared) · also books Elm St
Only the resource row lives in this domain; the policy rows are under Leasing & tours.
Leasing & tours 18 fields · 14 coming soon
Tour lengthfrom company30 minutes
Minimum noticeifrom company2 hours
Gap between toursifrom company15 minutes
Bookable days & same-day ruleiMon–Sat · same-day OK Mon–Fri
Tours per time slotifrom company1
Tour formats at this buildingifrom companyIn-person, Virtual
Self-guided accessifrom companyLockbox · code sent 1h before · ID required
Showing calendars offerediDana, Marcus · first free
Where prices & availability come fromRent roll
Application linkfrom companyapply.camelliares.com/camellia
Specials source · free month applies toWebsite scrape · first month
Holds: may Clara offer, for how longifrom companyYes · 48h · $300 deposit
Waitlist when nothing is availableifrom company
No-show handlingifrom companyRe-offer once
Inquiry routing: new hot leadifrom company{Leasing agent}
Inquiry routing: tour bookedifrom company{the calendar's owner}
Inquiry routing: application submittedifrom company{Property manager}
Listing photo / description freshness alertifrom company90 days
Listing auto-publish on notice and escalated-thread booking are NOT rows here — they are rung behaviours on the Autonomy card.
Maintenance 3 fields · 2 coming soon
Emergency additions for this buildingifrom companyBoiler failure, Elevator entrapment
Who Clara pages firstCrew order is set on the People card
Everything elseifrom companyInherits the company policy row by row
Same field labels as the company card, each rendered "from company" until touched. Replaces the "Maintenance Automation" card, which held one money rule and one phone number.
Turnover 3 fields · 1 coming soon
Inspect · ready within · tradesifrom companycompany defaults
Extra task types for this building2
Rooms to cover on the condition walkfrom company6
Renewals 4 fields · 2 coming soon
Open the renewalSet here60 days before lease end
Rent / terms / MTM / eligibility / negotiationifrom companycompany defaults
Rent-increase notice required by lawi60 days (Colorado)
Notice-to-vacate: what Clara doesCloses the renewal, starts turnover, drafts the move-out in AppFolio
Collections 8 fields · 5 coming soon
Collections law appliedColorado · supported · verified 2026-07
Law floorsearliest day 31 · hours 8–21 · notice 10 days
Start chasing when balance is at leastifrom company1 month · $50
Assistance programmes this building works withifrom companydenverhousing.org, +1
Eviction counselifrom companyHolt & Marsh LLP
Legal handoff: whenifrom companyManual only
Demand letter: default service methodifrom companyPersonal service
Demand partyCamellia House LLC → building page
Notifications 12 fields · 9 coming soon
Decision requestsifrom company{Escalation owner} + CC
Life-safety pageifrom company{Escalation owner} → on-call → inbox · all hours
Application awaiting reviewifrom company{Property manager}
Lease signed / move-out draftedfrom company{Accounting}
Renewal needs reviewifrom company{Property manager} · + text
In-house work ordersi{In-house crew}
Weekly owner reportifrom company{Owner contacts}
Legal-stage escalationifrom company{Escalation owner}
Second recipient (CC) per rowifrom companypicker
How much the office hears (override)ifrom companycompany
Reminders for youREMOVED — moved to Account
Maintenance tech phoneREMOVED — moved to the People card
Routing only — no people, no facts. Every row: event → a role, a person, or an inbox, badged with its source.
Compliance 2 fields · 2 coming soon
Quiet hours (narrower than company)ifrom company9 PM – 9 AM
Emergency definitions (additions)ifrom companyBoiler failure

4 · The building page — facts

What is true about this building with or without PropFlow: who, where, hours, money facts, access.

39 fields across 7 cards · 13 exist today · 26 coming soon

Property pageCamellia House
This building 4 fields · 2 coming soon
Public office line(303) 555-0142
Websitecamelliahouse.com
Listings feed URLicamelliahouse.com/availability
TimezoneiAmerica/Denver
People 16 fields · 13 coming soon
In-house crew · Carlos M.iTech · covers 12 buildings · first call here
In-house crew · Mike R.iHandyman · covers 4 · second call
Backup when unavailableiMike R.
Availability · quiet hoursiMon–Fri 7–4 · 9 PM–7 AM (his)
Owner / landlordiCamellia House LLC · 2 contacts
Legal counseliHolt & Marsh LLP (vendor, trade legal)
Property manager (primary)iDana Whitfield
On-site / assistant managerPriya S.
Leasing agentsMarcus L., Priya S.
Regional manageriJordan K. (Front Range)
Escalation owner (who owes an answer)iDana Whitfield
Backup / covering personiMarcus L.
Accounting contactiar@camelliares.com (inbox)
HOA / association contacti
Assistance programmesidenverhousing.org
When nobody is namedmail goes to camellia@camelliares.com
One row per role, one real record per row, one resolver. Every row survives cancelling PropFlow.
Owner access 9 fields · 9 coming soon
Reportsi✓ granted
Financialsi✓ granted
Occupancyi✓ granted
Work ordersi✓ granted
Documentsi✓ granted
Conversationsi— not granted
Buildings this owner seesiCamellia House, Elm St
Owner’s own viewiOpen portfolio intelligence →
One checklist per ownershipi2 owners on this building
Decided 2026-09-08. “Owner” here means the property owner (landlord) — the party holding the deed. Not org_admin (the customer’s own top-level admin) and not the PMS credential holder, which is what Property.ownerId actually is (types.ts:3371). Three different things, one word; this card is the third-party landlord.
Leasing facts 5 fields · 2 coming soon
Office hours · holiday closuresfrom companyMon–Fri 9–6 · 11 federal
Where to meet for a touriLeasing office, Building A
Rental criteria (as published here)ifrom companycompany standard
Fees & deposits · pet policy · lease terms · fee catalogfrom company12 items
Current specials1 month free on 12-mo
Lease policy (facts) 4 fields · 2 coming soon
Late fee and grace days5 % after 5 days
Notice period the lease requires from a residenti60 days
Legal jurisdictionUS-CO
Demand party: landlord legal name · remit-toiCamellia House LLC · PO Box 1200
Access & entry 5 fields · 5 coming soon
Entry notice required by lease/lawi24 hours
Key box / lockbox location and codeiFront office · ••••
Gate / building codes, alarm notesi••••
Utility shut-offs (water, gas, electrical)iBasement, NE corner
After-hours accessiCall (303) 555-0191
Go-to vendors 3 fields · 0 coming soon
Plumbingfrom companyAce Plumbing
Electricalfrom companycompany list
HVACSet hereSummit Mechanical
The roster is a fact. "Dispatch to them without asking" is the Autonomy rung, not a row here.
Systems & appliances 2 fields · 2 coming soon
Building systemsiBoiler (2019) · Elevator · Roof (2015)
Per-unit appliance registry + warranty endi48 units · 31 under warranty

5 · Admin — PropFlow staff

Ceilings, arms under soak, provisioning, and the watch list.

49 fields across 12 cards · 31 exist today · 18 coming soon

Admin SettingsPropFlow staff only
Autonomy ceilings 2 fields · 2 coming soon
Highest rung per module, per buildingiMaintenance: Autonomous (Camellia) · others: Act with approval
Platform spend capi$5,000 / job
Watch list 12 fields · 2 coming soon
PropFlow CC on this building's decision requestsper building
Leasing-activity Slack channel + mentionleasing-camellia · @fede
Holds channel (fallback alerts)alerts
Stuck-matter surface channelops
Fair-housing hold ping · daily review · nudge digestchannels
Shadow modes · isTest · sandbox recipient allowlistper building
Impersonation audit · MFA resetactions
Email shadow · SMS shadow (per building)
Lane stage (off · shadow · live) per modulelive · live · shadow
Test property
Activation logi"Live since 3 Sep, by Fede"
Change budget & failure tolerance this weeki3 / 1
Number provisioning 3 fields · 3 coming soon
Buy / import Twilio number → org pooliBuy →
Webhook / messaging-service wiringiAll green
Pending customer requestsi2
Voice agents 2 fields · 1 coming soon
Agent ↔ number / building bindingi3 agents · 38 buildings
Staging branch numbers2
PMS account registry 1 fields · 1 coming soon
Account slugs (multiTenantConfig)icamellia, situs
Leasing rollout switches 4 fields · 0 coming soon
Tour pipeline v2 · channel-matched notifications · tour-window matchingon · on · on
Escalated-thread tour booking allowlist4 buildings
Tour-request receipt on PROPOSEDon
Public-listings sync modeportfolio-homes
Maintenance arms 5 fields · 1 coming soon
Photo-deferral armon
Vendor dispatch env armarmed
Workflow-owned dispatch allowlist3 buildings
Maintenance capability stage per buildingmirror of the rung
Operating mode (on-site vs corporate)ion-site
Renewal & collections arms 8 fields · 1 coming soon
Renewal scanner (auto-start)
Renewal sending to real tenants
Holdover → month-to-month conversion
Scanner exclusions (person ids)3
Collections halt (emergency brake)
Emailed NTV firm routingarmed
Supported collections jurisdictionsiCO ✓ · CA declined · 48 unsupported
Leases-ending digest (temporary opt-in)2 buildings
Coming-soon governance 4 fields · 4 coming soon
Settings registryisrc/lib/domain/settings/registry.ts
Pages, palette index and this wireframeigenerated from the registry
Drift testsi3
Graduationione PR flips status + adds writer + reader
Three ad-hoc "coming soon" conventions exist today (a select label, a pill, an accordion body) and no registry. The product and the wireframe drift the moment they are two documents.
Kill switches 3 fields · 1 coming soon
Seven default-on kill.* switches
Collections halt
Return Clara to answer-or-park (this customer)iPress →
Arms under soak 2 fields · 0 coming soon
20 send arms · 7 kill switches · 2 runtime switchesgrouped by control
Per-property allowlists (workflow dispatch, operating mode, rollback ids)3 · 1 · 0
Access 3 fields · 2 coming soon
Roles → tab matrix9 roles
Modules per organizationiglobal today
Impersonation audit (actingAs / realUser)i

6 · The vendor record

Not a settings page: facts about a vendor the company deals with.

10 fields across 1 cards · 3 exist today · 7 coming soon

Vendors › Ace Plumbing
Vendor record (the org directory) 10 fields · 7 coming soon
Company, trade, specialties, contactsas today
Crew (in-house) per contact
Quiet hours per contacti9 PM – 7 AM
Certificate of insuranceiHartford · $1M · exp 2027-03
License number, state, expiryiCO-EL-4471 · 2027
W-9 on filei
Rates: hourly · trip · after-hours ×i$95 · $75 · 1.5×
Service areai12 buildings
Preferred channel and languageiSMS · Spanish
PMS facts (tax id, terms, hold payments, do-not-use)mirror
Not a settings card: half of "vendor management" is facts about a vendor.

7 · Module pages — read-only mirrors

Each shows what it is running with and links to the writer. None of them edit a setting.

16 fields across 4 cards · 9 exist today · 7 coming soon

Leasing / Maintenance / Renewals / Collections
Leasing › Prospects — "How this building leases" strip 7 fields · 1 coming soon
Tour length · notice · gap30m · 2h · 15m
Bookable daysMon–Sat
Calendars offeredDana, Marcus
Prices fromRent roll
Clara hereAct with approval
Prospect lanes4 active
Actions (not settings)iMark showed / no-show · Add to waitlist
Every chip links to its writer. The page never edits a setting.
Maintenance › Work orders — strip 6 fields · 4 coming soon
MaintenanceAct with approval · up to $500 (company default)
First calliCarlos (in-house) → Mike
Emergenciesicompany list + boiler, elevator
Vendor chasesdispatch 2 touches · quotes 3 touches
Turnoveriinspect next day 10:00 · paint, clean last · ready in 7 days
Vendorsi4 COIs expiring in 30 days
Every line links to its writer.
Leasing › Renewals — "Renewal Playbook" (mirror) 1 fields · 1 coming soon
Resolved policyiMin +3% · 6/12/15 · MTM +$150 · balance ≤ 2 mo
Collections — Policy drawer (mirror) 2 fields · 1 coming soon
Cadence21 / 28 / 31 days
Money rulesiLate fee 5% after 5d · enroll at 1 mo / $50 · CO floors

The event catalogue — who is told what

Every event that can notify someone, across all modules. The default recipient is a role; the company sets the default, a building may override. This is the table the Notifications routing rows are built from.

ModuleEventDefault recipientSet atToday
EscalationDecision request opened{Escalation owner} + CCOrg default · Property overrideexists
EscalationDaily reminder on an unanswered asksame, re-resolved liveinheritsexists
EscalationStill unanswered after N reminders → moved up{Regional manager} → {Org admin}Orgcoming soon
EscalationLife-safety page (gas, fire, flood){Escalation owner} → on-call → inbox, all hoursOrg · never offexists
EscalationForward to office / plain page / unknown-caller note{Property manager}Org → Propertyexists
EscalationMissed transfer call{Escalation owner} → inboxinheritsexists
EscalationPromise needs a human{Escalation owner}inheritsexists
EscalationFair-housing hold on a draftPropFlow watch list → {Org admin}Admin → Orgexists
LeasingNew tour / application / lease (activity){Leasing agent} digestOrg → Propertyexists
LeasingApplication awaiting review (+ reminders){Property manager}; cadence per personrouting Org → Property · cadence Accountexists
LeasingNew-lease package needs review{Property manager}inheritsexists
LeasingLease signed / renewal executed{Accounting}Org default · Property overrideexists
LeasingRenewal needs manual review{Property manager} email + textOrg → Propertyexists
LeasingLeases ending with no answer (digest){Property manager}Org toggleexists
LeasingVirtual tour: "your team calls at…"{Leasing agent}inheritsexists
LeasingStale leads weekly list{Leasing agent}Org toggleexists
LeasingRent-roll sync digest{Property manager}Org toggleexists
LeasingWeekly / monthly owner report{Owner contacts} → inboxOrg window · Property recipientsexists
LeasingTour booked / moved / cancelled{Leasing agent}inheritsexists
MaintenanceIn-house work order dispatched (SMS){In-house crew}Propertyexists
MaintenanceVendor call outcome{Property manager}inheritsexists
MaintenancePO required before dial{Property manager} (+ {Accounting})inheritsexists
MaintenanceQuote above the spend ceiling{Property manager} (review queue)Org ceiling → Propertyexists
MaintenanceWork-order milestones digest{Property manager}Org → Propertycoming soon
TurnoverMove-out drafted in AppFolio{Accounting} → {Property manager} → inboxinheritsexists
TurnoverMove-out date mismatch{Property manager}inheritsexists
TurnoverInspection scheduled / condition report ready{Property manager}, {On-site}Org → Propertycoming soon
TurnoverTurnover dispatch above cost cap{Property manager}inherits ceilingcoming soon
CollectionsPast-due / habitability hand-off{Property manager}inheritsexists
CollectionsEviction-flagged or uncured demand{Escalation owner} — not the landlordOrg → Propertyexists
CollectionsCounsel / court / programme mail arrived{Property manager}Propertyexists
CollectionsNo escalation owner named at a real building{Org admin} weeklyOrgcoming soon
AccountInvite accepted / role changed / removed{Org admin}Orgcoming soon
AccountNew sign-in / MFA enrolled or resetthe personcoming soon
AccountContact ceiling hitPropFlow watch list → {Org admin}Admin → Orgexists

Coming-soon governance: how the greyed rows stop lying

Three ad-hoc “coming soon” conventions exist in the product today — a select label, a pill, an accordion body — and no registry. The design and the product drift the moment they are two documents. So: one typed settings registry in code, from which the settings pages, the search index and this wireframe are all generated.

  1. Declare. One row per field: id, level, card, label, control, inheritance chain, mode (ceiling / default / fixed), status (live / coming soon / staff only), which field stores it, which route writes it, since when, and the decision page that decided it. A row with no decision link fails lint.
  2. Show. A coming-soon row renders through one component — greyed control, real label, ⓘ with the one-line why. A page cannot render a field the registry does not list.
  3. Gate. Three drift tests: every rendered field has a row; a coming-soon row has no writer (the same fence that protects hand-off mode today); a staff-only row renders only under Admin.
  4. Graduate. One PR flips the status, adds the writer and the reader; the tests refuse one without the other. Nobody un-greys at runtime — no flag, no env, no toggle. The wireframe re-renders from main, so the design cannot say one thing while the product says another.

The decision register

Status 2026-09-08 — CLOSED. All 22 decided. Ten by button, twelve in Gera’s own words (the decisions page). Two reversed the recommendation on this page: seats (row 8) and rental criteria (row 9), the second toward more caution than was proposed. Each row below keeps its original recommendation underneath the answer, so a reader can see what was rejected as well as what was chosen.

Every genuinely open choice the six passes surfaced, deduplicated, each with a recommendation. Answer by picking.

#DecisionRecommendationRaised in
1Number topologyDecided 2026-09-08 (Gera): any shape — one number may serve the company, a group of buildings, or one building, mixed within one customer; the settings page shows the binding for wherever you are in the nav (his own words are on the decisions page). Was: One line per building, voice and text together, auto-assigned from the company pool at onboarding. A company main line is opt-in, never the default.Identity
2Calendar of record for toursDecided 2026-09-08 (Gera): same as the number: a calendar may be company-only, shared by some buildings, or one per building, in any mix; a person’s offered calendar is one more source the building can bind. The unread person-level connection still stops being written until it is read. Was: Offered personal calendars by default (a person offers theirs; the building picks; first-free, round-robin optional); company shared calendars as the scale path. Stop writing the unread person-level connection until it is read.Identity · Leasing
3Sending domainDecided 2026-09-08 (Gera): the from-address is a binding like the number (company, group or building). On the domain itself his standing rule applies — “we work around their system” — so the customer’s own domain when they have one, the PropFlow fallback when they do not. Was: The customer's own domain with a verified-status chip; clara@<customer>.propflowai.co as the zero-setup fallback.Identity
4Platform spend ceilingDecided 2026-09-08 (Gera): in his words: greyed out as a placeholder with the rules shown; the value is governed by the property when set there, otherwise the company’s — “we would want both, where property takes precedence”. Read with row 6 (the cap wins), this is exactly the ceilings-vs-defaults split above: the company holds a default the building may override and a cap the building cannot exceed. The $5,000 / $1,500 figures were not decided; they stay as the placeholder’s sample values. Was: $5,000 per job is the most any customer may set. Autonomous dispatch above $1,500 needs the company cap raised by an org admin, not a PM. Under the ceiling, "Act with approval" auto-accepts quotes — otherwise the ceiling means nothing.Autonomy · Maintenance
5What "Off" meansDecided 2026-09-08 (Gera): accepted — “Hand it to a named person, never silence.” Was: Park to a named human, never silence. Today capabilityStage.off equals shadow suppression, which is silence — that changes before Off is offered. For collections, onboarding forces a choice and an Off building shows a persistent banner.Autonomy · Collections
6Company cap vs a building already above itDecided 2026-09-08 (Gera): accepted — “The company cap wins; the building is clamped and labelled.” Was: The cap wins. The building clamps and its badge reads "Clamped by company cap on <date>". No grandfathering.Autonomy
7What the plan gatesDecided 2026-09-08 (Gera): in his words: “all of it should be configurable by the customer … the admins for those accounts could configure things like autonomy, compliance and contact limits.” My reading, not his click: nothing is locked by the plan; what varies is the role — a customer admin configures autonomy, compliance and contact limits, a regular user does not. That is consistent with the Admin ceilings above (the customer configures inside a platform limit). Was: Modules, channels and languages only. Autonomy, compliance and the contact ceiling are never plan-gated — safety is not an upsell.Plan
8SeatsDecided 2026-09-08 (Gera): overruled — “Let’s do per unit and then have 12 users per account cap.” Nothing counts users today, so the cap needs a row and a behaviour when it is reached. Folded into the architecture’s phase P7 (staff and login). Was: None. Unlimited users, pay per unit; unitCount already exists and there is no seat concept to defend.Plan · Team
9May Clara state published rental criteria?Decided 2026-09-08 (Gera): overruled, toward caution — “No, I think there’s fair housing rules… the safe answer, we don’t want to hand off to the person. We want to maybe do ‘that’s something we would review when your application comes in’… we want to play it safe.” So Clara neither states the criteria nor transfers: she says the application is reviewed when it arrives. The criteria card comes off the design. Was: Yes — one sentence, verbatim from the company criteria sheet; never "you would / wouldn't qualify". The transfer stays for "would I qualify?"Leasing
10Renewal negotiation floorDecided 2026-09-08 (Gera): accepted — “Yes, a company-level floor, default zero.” Was: Yes, company-level, default 0% (today's behaviour), never above the minimum increase. Everything outside the floor and the offered terms still escalates.Renewals
11Payment plansDecided 2026-09-08 (Gera): accepted — “Never on her own; propose for PM approval once lawyers sign off.” Was: Never, as the default even after the field exists. Ship "propose only, PM approves" greyed until counsel signs off per state.Collections
12Autonomous for collectionsDecided 2026-09-08 (Gera): accepted — “No; PropFlow unlocks it per state after legal review.” Was: Never for a customer. An Admin unlock per state after counsel sign-off; the customer sees the rung greyed with "Requires PropFlow legal review for <state>".Collections
13Who owns staff assignmentDecided 2026-09-08 (Gera): the writer follows the nav — a building selected edits that building’s people, no building selected edits the company’s — and both write the same graph, so there is one fact and two views of it. Was: Org › Team owns who works where. The building's People card only chooses which assigned person is primary or escalation owner here, and adds non-staff rows (crew, owner, counsel). Two writers for one fact would drift.People
14Is the maintenance tech a login or a crew member?Decided 2026-09-08 (Gera): accepted — “Either: crew gets texts with no login; app users get a staff role.” Was: Crew = an in-house vendor membership (no login, gets SMS). A tech who needs the app = the staff role. The People card accepts either; the resolver reads the phone off the person.People · Maintenance
15The escalation ladderDecided 2026-09-08 (Gera): accepted — “Company sets the cadence within bounds; PropFlow is the last rung only.” The control (cadence bounds, the ordered role list) is this page’s; the path change — PropFlow’s Slack from first rung to last, and only when no customer role resolves — is a code change in agents/clara and is taken by the architecture effort as a P7 row. Was: A company knob with bounds (ask again every 4–72h; stop after 1–5), then move up to the regional manager, then the org admin. PropFlow's Slack becomes the last rung, only when no customer role resolves.Escalation
16Expired vendor insuranceDecided 2026-09-08 (Gera): accepted — “Warn by default; companies may choose to block.” Was: "Warn" as the platform default; "block except emergencies" selectable at company level. Blocking by default strands jobs at onboarding when zero certificates are on file.Maintenance
17Vendors not in AppFolioDecided 2026-09-08 (Gera): accepted — “Yes, PropFlow-only vendors that a later sync links.” This also closed the architecture side’s open question on vendor identity: a vendor card with no engagement rows is the directory. Was: Allow a PropFlow-only vendor row the sync later links. Otherwise a Yardi or Buildium customer has no vendor directory at all.Maintenance
18Quiet-hours narrowing per buildingDecided 2026-09-08 (Gera): accepted — “Yes, narrower only.” ⚠️ The resolver must refuse a widening write rather than silently ignore it: a control that looks writable and quietly drops the value is worse than one that says no. Was: Yes, narrower only — the one compliance override a building gets. (One quiet hours, on the building's clock, stays settled.)Compliance
19Retention floorsDecided 2026-09-08 (Gera): accepted — “7 years conversations and audit, 4 years consent and opt-out.” Platform floors, not per-customer settings. Was: Conversations 7 years, consent and opt-out at least 4 years as coded, audit 7 years — and let the DPA cite the registry, not the reverse.Compliance
20Voice as its own capabilityDecided 2026-09-08 (Gera): accepted — “Yes, calls and texts are separate switches.” Was: Yes, separate from texting. A customer who allows texts but not calls is a real profile.Capabilities
21ToneDecided 2026-09-08 (Gera): accepted — “Three tested variants, greyed until each is tested.” Was: A three-variant evaluated select, shipped greyed until the variants are graded. Never a free-text persona field.Identity
22A level between company and buildingDecided 2026-09-08 (Gera): reversed. A group exists in the portfolio-architecture record as a binding target and a precedence rung (building → group → company → registry default). It is not a fourth settings page: it is where a shared number or calendar hangs, and what a value inherits from. Bulk-apply stays as the gesture for policy. Was: No. Region is a permission scope (assigned properties); a PMS account is an integrations binding. Build a bulk-apply gesture on Property Settings instead.Model

What onboarding must collect — and where it lands

Onboarding is the first write, not a separate store. Nothing should be enterable only at onboarding, and nothing required before Clara runs should be settable only by a script.

Verification note. Each domain pass cited file and line for its claims about current code; the integration re-read a sample from every pass (the settings resolver’s “no global fallback” header, the offer-only lead time, the absent screening criteria, the absent vendor insurance fields, the second vendor chain in turnover policy, the delinquency threshold saved to two fields, the collections review-gate ruling, the Colorado-only jurisdiction registry, the stuck-matter Slack surface, the silent no-owner paths, the nag constants, the user-gated settings route, the shadow-equals-off comment, the per-building calendar read, the per-user PMS credentials, the onboarding number literal, the timezone with no writer) and found every one verbatim. Where an agent inferred rather than read, the row says so.

The big picture: how not to become AppFolio

Written 2026-09-08, at the point where the surface is about to be filled in. Onboarding new companies is the driver, and the storage shape is the part that stops being changeable once real customers have values in it.

What the incumbents get wrong, and why it is one decision away

AppFolio, Yardi, Buildium, RealPage and Entrata all arrived at the same place by the same road: every module grew its own setup screen, owned by its own team, and nobody merged them. The result is a settings tree three or four levels deep where the same idea — who gets notified, office hours, late fees — is configured in two or three places under different names. That is an industry pattern rather than a claim about any one screen, and it is why each of these vendors sells implementation consulting and why “where do I turn that off?” is a top support category.

Three specific failures. PropFlow is one decision away from each:

What to steal, and whether it fits us

PatternWhere it is provenFits PropFlow?
Scope in the URL — the team / project or org / repo split is a path segmentVercel, GitHub, LinearYes, and it is the one we violate. Organization and property are exactly their team and project.
Inheritance with a visible “inherited from” stateGitHub org → repo policy, Vercel team defaultsYes. Already the proposal. The badge is not decoration — it is how a manager answers “is this building special?”
A parent can lock a value, not merely default itGitHub enterprise policyYes. This is how “Autonomous is staff-only” gets enforced rather than hoped for: the platform sets a ceiling, nobody below can exceed it.
Settings answer the global search boxLinear, Stripe, ShopifyYes, with one precondition — see below.
One canonical writer, read-only mirrors elsewhereGeneral to all of themYes, and overdue.
Progressive disclosure — a few switches visible, detail underneathStripe, IntercomYes. Fifty-one knobs on one screen is a tree; six cards of three to five visible rows is a page.
Test / live mode switchStripeNo. A manager has no test mode for a real building.
Settings that go below the lowest real objectNotion per-pageNo. Nothing below the property. No per-unit knobs, ever.

The one rule

“If it decides what Clara does it goes in Settings; if it describes the building it goes on the building page” is right in spirit but loses every argument at the edges, because Clara reads almost everything. Pricing decides what she quotes. Pool hours decide what she says. Sharpen it into a test you can run in your head:

Would this still need to be true if you cancelled PropFlow tomorrow?

A fact was in the filing cabinet before we arrived and survives us. A setting only exists because Clara does. Clara reading a fact does not make it a setting.

That test picks the surface. A second one picks the level, and it is the one that answers “whose notification is this?”:

If you change it, who feels the difference?

Run them in order: first which surface, then which level. Neither question answers the other.

Worked: the word “notifications” means two different things

This is the case that trips everyone, because both things are called notifications and both are real.

Who gets toldHow I want to be told
ExamplesEscalation owner and CC, maintenance tech phone, renewal contact, who receives the weekly owner reportOne daily digest or every event as it happens; how many reminders about my pending approvals; how often
It is really aboutWho staffs this buildingMe
Change it and…a different person gets pagedmy inbox looks different, nobody else's does
LevelProperty (some inherited from the company)Account
TodayCorrect — Property Settings › Emails & reminders › Who else gets notifiedMis-scoped. There is no Account-level version. “Reminders for you” sits on Property Settings and is stored per building (pmActionReminders on the property's leasing settings), so a manager with twelve buildings tunes their own reminders twelve times and no page anywhere says how they want to be reminded.

The Property Settings page already knows these are two different things — its own subtitle says “Reminders for you” are emails about your to-dos and “Who else gets notified” are emails to other people. It splits them into two blocks on one card. The correction is small: the first block moves up to Account, the second stays.

A trap on the same test, worth naming. A company policy earns a place on your Account page only if it constrains you personally — two-factor, because you have to enrol; a cap on your own reminder cadence, because it bounds a setting of yours. It does not earn a place merely by being a rule you are subject to. Resident quiet hours are the clean counter-example: they are a real company policy, but changing them alters what residents receive, not what you do. Run the level test on them and the answer is “everyone at this company”, so they live at Organization with a per-building override for state law — and never on a personal page, where their presence would imply they are yours to bend. This corrects an earlier draft of the Account wireframe above, which listed them under “set by my company”.

Honest counter-argument: you might genuinely want more nagging on one difficult building. That is fine and needs no special case — Account holds the default, a property may override it, exactly like every other inherited value. What is wrong today is that there is no personal default to inherit from.

Applied to real knobs

KnobTestHome
Rent, fees, concessions, pool hours, pet policyWould exist without usBuilding page. Clara quotes them; she does not own them.
“Autonomously send renewal offers”Meaningless without usMoves off the building page into the Settings Autonomy card, on the same ladder as maintenance. This is the accident the rule exists to fix.
Leasing follow-up cadence (text again after 2 days, then 5)The hard one. A whiteboard could hold it, so it feels like a fact — but the knob is not what our policy is, it is when Clara actsSettings. The Leasing page shows “Running with: 2d / 5d” and nothing editable.
Preferred vendors by tradeTwo knobs fused into one. “Ace Plumbing is our plumber here” would be true without us; “dispatch to them without asking” would notSplit them. Roster to the building page and org directory; the dispatch decision to Settings. Today they are fused, which is why nobody can say whether editing the roster changes behaviour.
Quiet hours (no texts after 9pm)Feels like company policy, but only ever governs Clara's outboundSettings, organization level, inherited and overridable. Most managers will meet the inheritance badge here first, so make it a good one.
The rule checks out against the inventory. It was written without looking at the ~97-knob table, then tested against it. Everything the rule calls a fact — business hours, holiday closures, qualification rules, the in-house handyman roster, turnover task types — had already been independently assigned to the building page. Everything it calls an instruction — hand-off mode, shadow mode, the auto-approve ceiling, dispatch autonomy — had already been assigned to the Autonomy card. Two routes, same split. One honest exception: company name, logo and billing address fail the test as facts, but there is no company page to put them on. Leave them in Settings under Company profile and note the exception rather than building an org page for three fields.

Settings search: yes, at card level, and not until scope leaves the cookie

Removing the settings rows from ⌘K on 2026-09-07 was correct, and the code comment states the law to build to: a search result may only exist if its link fully determines what renders. A row that lands on a page which then consults a cookie to decide what to show is a lie, and a support ticket. Today only /settings/account is a real address; /settings resolves to Organization or Property from propflow-property-filter — and that is the global picker shared with Dashboard, Leasing and Maintenance, so this is not a settings-local problem.

  1. Put scope in the URL. /settings/organization/<card> and /settings/property/<id>/<card>. Bare /settings keeps today's follow-the-picker behaviour so the sidebar link is unchanged. Landing on a property settings URL sets the picker rather than reading it — the same way opening a building page already tells you which building you are in. The building page is deep-linkable; settings is the odd one out.
  2. One settings registry, in code. Every knob declared once: id, label, level, card, keywords, default. The cards render from it, the inheritance resolver reads it, and the search index is generated from it. The hand-written index (24 pages + 18 sections) is fine for pages and will rot the day it has to track ninety-seven knobs. The registry is also what makes the inheritance badge and the audit trail nearly free.
  3. Index cards, not fields. A result reads CallsAfter-hours and voicemail, with a chip naming the building or Organization. When no building is picked and the hit is property-level, the row says Property setting — choose a property and the second step is the building list. Never guess a building.
  4. Field-level search later, and only with scroll-and-highlight. A field hit that dumps you at the top of a twenty-row card recreates the same broken promise one level down.

Cost: the route change and picker sync is a day or two; the registry is the real work, and you need it for inheritance regardless; generating search rows from it is an afternoon. Field-level search is a week not to spend yet.

Decide now, defer the rest

Before the surface fills in — these get expensive or impossible once companies are onboarded:

  1. Apply the rule. Move renewal autonomy into the Autonomy card, demote module-page config to read-only mirrors, split the vendor roster from the vendor dispatch decision. Do it before customers learn the current homes.
  2. The store inherits, it never copies. One table keyed by scope kind, scope id and key; absence means inherit; the resolver walks property → organization → platform. Do not write resolved values onto each property for speed. That is the incumbent mistake, and in practice it cannot be undone.
  3. Stable string ids for every knob. They end up in URLs, audit rows, search entries, exports and support calls. Renaming one after launch is a migration.
  4. Scope in the URL. Cheap now, painful once links are sitting in customer emails.
  5. Ceilings at the platform level, not just defaults. One autonomy enum used by every module, with a platform row that caps it.
  6. Audit from day one — who changed what, from what, to what, when. Trivial against one writer now, impossible to reconstruct later, and the first “why did Clara do that?” call will ask for it.
  7. Convert the hard-coded early-customer behaviour into rows (the categories the customer-identifier fence already tracks, plus the name and timezone sweep in the section below). Every one of those is a knob that does not exist yet, so the inventory is not really ninety-seven until they are counted.
  8. Decide whether a level will ever sit between company and building — region, portfolio, owner. Judging by how management companies are structured, it will. Do not build it; write the resolver as a walk up a list of scopes rather than two hard-coded lookups.

Safe to defer, because none of it touches the store or the ids: field-level search, bulk apply-to-these-twelve-buildings, property templates for onboarding, change-history UI, per-role card visibility, export/import, a settings API.

Never build: per-unit settings, and a second writer for anything.

The decisive pass: every knob adjudicated

2026-09-08. Gera: “I don't want to tell you to do individual things … go through each one, break it down, validate the current designs.” This is that pass. It applies the two tests and does not relitigate them. Claims marked verified were read in the codebase; claims marked inference are reasoning from the business.

The building page: what belongs there, and the three tells

Asked directly of a live building page (/properties/<id>) and its three configuration cards: turnover policy, vendor job reference, renewal policy. None of the three belongs where it is — and each is wrong for a different reason. That is what makes a single “move it to Settings” answer useless and a policy necessary.

On the page todayWhere it is stored (verified)Verdict
Turnover policy
inspection delay, default trades, finishing trades
Inside PropertyKnowledge — the store of what Clara knows and saysA rule filed in the facts store. None of it is true about the building; all of it instructs Clara. → Property Settings › Maintenance, inherited from the company.
Renewal policy
rent strategy, max increase, terms, MTM premium — plus “Eligibility & autonomy”
Also inside PropertyKnowledge, with an autonomy toggle embedded in the editorTwo faults at once. The rules are misfiled like turnover; and an autonomy switch is hiding inside a policy card. → Rules to Property Settings › Renewals; “autonomously send renewal offers” to the Autonomy ladder, beside maintenance.
Vendor job reference
work order vs purchase order
Top-level on Property. Its own comment says: “this is PMS configuration”Right kind of thing, wrong subject. It is a fact — but a fact about the PMS account, not the building, and one account serves the whole company. → Organization › Integrations, overridden only where a building is bound to a different account.

The policy, in one line and three tells

The building page answers “what is true about this building?” Settings answers “what should the software do?”

If a card cannot be read as a sentence about the building — its address, its hours, its units, its fees, its people — it is not a building-page card.

In practice nobody adjudicates from the principle; they notice a smell. These are the three that catch essentially every misfiling in the inventory:

  1. A rule filed in the knowledge store. PropertyKnowledge is what Clara says; a rule is what Clara does. Anything in that store which changes behaviour rather than an answer is in the wrong house. Catches: turnover policy, renewal rent rules, late fee and grace days.
  2. A fact about something other than the building. The right kind of thing attached to the wrong subject. A fact about the PMS account belongs to the company; a fact about a person belongs on the person. Catches: vendor job reference, Clara's PMS display name, delivery path, handyman quiet hours.
  3. An autonomy switch inside a policy editor. If one card holds both “max increase 8%” and “do it without asking”, the second one belongs on the ladder. A policy says what good looks like; a rung says how far Clara may go alone. Catches: renewal autonomy, and it is how the maintenance/renewal split happened in the first place.

A fourth tell, from the level test rather than the surface test: the label says “you” or “me” but the value is keyed to a building — which is how a personal reminder preference ended up stored once per property.

What survives on the building page after all three tells are applied: address, unit list and status, occupancy and the metric cards, pricing and fees, concessions, the knowledge sections Clara quotes, office hours and holidays, and the People card — who manages, who fixes, who owns. Every one of those reads as a sentence about the building. Nothing left on it instructs Clara.

1 — People are not settings

The question “where does the maintenance tech go?” has no satisfying answer because the thing being placed is not one kind of thing. Verified: a person responsible for something at a building is stored four different ways today.

WhoStored asShape
Handymen / in-house crewProperty.handymanVendorIdsReferences to real vendor records
Maintenance techProperty.maintenanceTechPhoneA bare phone string
Escalation owner and CCescalationOwnerEmail / CcEmailBare email strings
Staff and on-site managersUser.assignedPropertyIds + a spine PersonRoleReal accounts with permissions

The decision: a person attached to a building is a role, never a setting. Settings may hold a routing decision — when this happens, page whoever holds that role — but the person lives once on the identity spine and every notification resolves through it at send time. Three shapes cover every “who” in the inventory:

The test for the third row: if this address stopped being read, would a specific person be at fault? If yes, it is a person wearing an email address. Most of today's strings fail it.

What the strings already cost, in code we have

In plain terms, what strings cost you: the tech changes their number and you edit every building and miss one, which then pages a dead number silently. One person covering six buildings appears six times with nothing linking them. A phone string cannot be told “you may approve up to $500”, which is precisely what the Act with approval rung needs. The audit trail says an email address instead of a name and a role. And when someone leaves, nothing ends — the string keeps getting paged.

The model

The building page gets a People card — one row per role, each pointing at a real record. It is the canonical writer for who.

RowShapeBacked by
Property manager, on-site managerRolePerson + PersonRole. Read-only mirror — the Org's Team page owns the assignment, so the building page never becomes a permissions editor.
In-house crew (tech and handymen)RolePerson + VendorMembership with isInHouse. Tech and handyman are one role: the person is who you page, the company is where the work order is assigned. Both derive from one membership, and both string fields retire.
Owner (landlord)Contact recordAn owner entity plus named contacts. Inference: owners are usually an LLC, so this needs a company-shaped record rather than a bare person. demandParty stays as the legal-name fact — it names a legal entity on a legal instrument, which is genuinely a fact.
Legal counsel (eviction firm)Contact recordA vendor company with trade legal. It is a vendor; nothing about it needs a new mechanism.
Assistance programmesStringAn inbox nobody owns. Correctly a string.

Settings holds routing rows, not addresses. Each row is event → recipient, where the recipient is a pointer: a role (whoever holds it at send time), a specific person, or an inbox. Escalations default to the PM role; lease-signed goes to accounting; the weekly owner report goes to the owner role. Every row badges its inheritance like any other setting. Migration is uneventful: backfill each string into a person and a role, let the resolver fall back to the legacy string until nothing reads it, then delete the field. No customer-visible change on day one.

2 — The five families you named

Follow-ups and chases: one control, five lanes

They are one knob wearing five hats. Every lane is the same shape — attempts × interval × channel × stop-when. What differs is who is on the other end and whether the lane is legally regulated. So: one Follow-ups card at Organization, one row per lane (prospect inquiry, re-engage, tour confirm, post-tour, vendor chase, renewal chase, collections chase), each expandable, each overridable per building. Above them, one contact ceiling at Organization only, with no property override — that is the company's compliance posture, and a per-building override is how a complaint starts. Post-tour follow-up is a lane of this, not its own knob. PM action reminders are not a chase; they nag your own staff, and they are handled below.

Money: one ceiling, and two things that are not ceilings

One autonomous-spend ceiling: Clara may commit up to $X without asking. The turnover cost cap is a sub-line of it, not a second ceiling. “Big-ticket items” needs no knob at all — it is simply anything above X, which is the approval rung doing its job. Two imposters: the delinquency threshold is measured in months and gates whether a renewal offer goes out, so it is a renewals policy rule, not a ceiling; and late fee and grace days are in the lease whether or not PropFlow exists, so they are a building fact.

Clara's identity: three things, not one

Brand (what she calls herself, sender name, tone) is Organization — every channel, every building. Lines (phone numbers, PMS display-name binding, from-address) are provisioned facts, shown read-only and never typed. The greeting line should not be a field at all: it is brand plus building name, derived. An editor there invites free text into a spoken prompt that is evaluated.

Delivery and routing: this is Integrations, and most of it is org-level

The delivery path and Clara's PMS display name are properties of the PMS account, and one database equals one organization. Both move up to Organization, inherited down, overridden only where a building is bound to a different account. The property inbox and the listings URL are facts about the building. What remains on Property Settings is bindings, all read-only.

Hours: two concepts, do not merge them

When the building is open (office hours, holidays) is a fact — building page. When Clara may contact people (resident quiet hours; handyman quiet hours, which belong to the person and follow them across every building) is a protection rule — Settings. Scheduling capacity (duration, lead time, buffers, weekday policy) is an instruction to the booking engine. Collapsing them would be wrong because they answer to three different people: the office manager, the compliance officer, and the leasing lead.

3 — What actually changes

Moves

KnobFrom → toWhy
Company nameUser.companyName → the organizationOrg identity sitting on a personal field
Clara's PMS display name; messaging delivery pathProperty → Organization (inherited)Both belong to the PMS account, which is org-level
Escalation owner; renewal contact; owner report recipientsEmail strings → People card roles + routing rowsPeople stored as strings
Maintenance tech phone; handymen→ One “in-house crew” role on the People cardTwo fields describing one person
Eviction firmScript-set strings → a vendor company with trade legalIt is a vendor
SMS enabled; email replies; vendor quote and dispatch mailA global row any signed-in user can flip → Organization capabilitiesWrong level and wrong permission today
Hidden-from-sync propertiesA per-user list → OrganizationA personal denylist governing company-wide sync
Turnover policy; renewal rent strategyThe knowledge blob → Property SettingsRules living in the facts store
Delinquency thresholdAutonomy card → RenewalsNot a money ceiling
Late fee and grace days; application link; listings URL; property inboxSettings → building pageAll four exist without PropFlow
Vendor job reference (WO vs PO)Building page → OrganizationA convention of the PMS account
All four chase cadencesModule drawers as writers → Settings writes, drawers mirrorFive drawers each writing their own copy is the whole scattered feeling

Splits — one row that is secretly two

RowThe fact halfThe decision half
Transfer destinationThe office and emergency phone numbers are building facts“Where does Clara transfer to” is a routing row defaulting to that number. Today they are one field, so the number is stored twice.
Escalation owner + CCOwner is a role; the CC is an inbox. Verified: in the escalation bake-gate tests the CC is a PropFlow address on the Willows bench fixture — PropFlow watching its own bake. That is an internal watch list, not a customer setting.
Signature / sender identityThe from-address is the property inboxThe display name is company brand
Weekly owner reportRecipients are the owner roleThe window (7 vs 30 days) is a company habit
MFA and SSOThe company mandates; the person enrols. Two rows, two levels.
PM action remindersThe building has no half — delete the property row“Remind me, this often” is Account. “Staff get reminded at all, up to this cadence” is Organization.

Right where they are, against instinct

These exist to stop the same argument being had twice.

Should not exist

The greeting-line editor (derived). Post-tour follow-up delay (a lane of the cadence card). Owner escalation recipient (the same field as escalation owner). The tech phone and the CC as customer fields. The leases-ending digest (its own doc says temporary). Free-text collections tone (enum or nothing). Vendor transfer-first and shadow mode (activation states, not switches). The workflow dispatch allowlist (a cutover flag). Tour buffers (not built — do not build until asked).

4 — Does the four-level design survive? Yes, with two amendments

Account is thin, and that is fine. A level is justified by who feels the change, not by row count, and “only me” is a distinct audience. It is also thin partly because rows were mis-filed onto Property: the reminders row alone justifies the level, and the giveaway is a card headed “Reminders for you” sitting on a per-building page. A useful rule falls out of it: if the label says “you” or “me” and the value is keyed to a building, it is mis-scoped. This is also the first place the chain runs company → account rather than company → property, which is the honest shape for a preference as opposed to a policy.

Organization earns its place, but read today's page as intent rather than state. Its job is to be the defaults level — every inherited row is authored here and merely overridden per building. The honest statement: roughly nineteen designed rows, zero writable, one working inherited chain. Until the organization writer exists, every “from company” badge in the wireframes above is fiction. That makes the sequence binding rather than advisory: organization writer, then the generic resolver, then the cards.

No fifth level. The two candidates are region and PMS account. Region is a permission scope, already handled by assigned properties; PMS account is an integrations binding. What operators actually want for “these six buildings” is a bulk-apply gesture on Property Settings, not a new level. Inference: revisit only if one customer runs several PMS databases or dozens of buildings under genuinely separate regional policies.

The building page and Settings stay two surfaces. Different readers (an agent opens the building page daily; property settings change a few times a year), different provenance badges (facts carry scraped / manual / PMS-synced; settings carry set here / from company, and mixing the two vocabularies is how a scraped fact gets mistaken for a company policy), and different blast radius (a settings change re-routes Clara; a fact change corrects the world). They need one seam, not one page: the People card is the canonical writer for who, and Settings routing rows point at those roles. Link both ways in the header.

Amendment 1 — the Autonomy card holds two things only: the ladder and the spend ceiling. Everything else that drifted onto it is either a rung behaviour or a module policy row. A card with fourteen switches is not a ladder.

Amendment 2 — Admin gets a named watch list for the per-property CCs, holds channel and shadow modes PropFlow staff use to observe a bake. Naming it is what stops those leaking into customer fields, as the escalation CC already did.

Verification note. Claims about classify-origin-thread.ts, demand-context.ts, VendorMembership, resolvePmContactEmail and the single built inheritance chain were read in the codebase today. Two claims from the drafting pass were corrected before publishing: a quoted comment on escalationOwnerEmail that does not exist in the code, and a CC address attributed to a customer's production configuration when it appears in a bench test fixture.

In one screen

The five decisions, as multiple choice

Each has a recommendation. The criteria in the next section are what the recommendation is derived from; the applied table further down is what each choice implies knob by knob.

Q1 — Where do the deciders live (Clara acts / asks / stays off)?

  1. Recommended. One Autonomy card on Property Settings, one row per module (Leasing, Tours, Maintenance, Renewals, Collections, Conversations), each row a four-rung ladder — Off / Suggest / Act with approval / Autonomous — plus that module's decider parameters (spend ceiling, delinquency threshold, voice-call-on-offer). Each module page shows a read-only pill ("Clara here: Act with approval") linking to the card. One writer, one place; the constitution's one-switch-on-the-property rule (Art. IV.3) and shadow/live-on-the-record (VII.4) both land here. The ladder maps onto fields that already exist (capabilityStage, handoffMode, the send arms) rather than a new one.
  2. Each module page owns its own autonomy card as the writer. Rejected: it puts an arm next to a queue where a PM toggles under pressure, and it recreates the "which of the two places is real" problem Gera named.
  3. Settings only, no mirror. Rejected: the review queue already needed inline copy explaining why items are there; the mirror is that explanation.

Q2 — Do Property settings inherit from the Organization?

  1. Recommended. Yes, for knobs that are the company's habit with the building as the exception: platform default → Organization → Property. Absence is inheritance; a stored value is an override. One resolver returns { value, source } and the UI renders source as the badge ("Inherited from Organization" / "Overrides organization — Reset"), so the badge cannot disagree with what the runtime used. This is the vendors chain the product already runs (resolvePreferredVendors), generalised. Knobs that are physically per building (phones, calendars, Twilio numbers) and the autonomy rung itself never read the org row, so an org edit can never arm a property.
  2. Property-only, as today. Rejected: every operator with more than one building re-enters the same tour length, application link and reminder cadence per building, and an org-wide change never propagates.
  3. Org-only. Rejected: pricing source, office phones and calendars are genuinely per building.

On Gera's three examples: tour duration and application link become org default with property override; transfer destination stays property-only — it feels org-level only because a single-property customer collapses the two levels, which the UI should handle by hiding the split for single-property orgs (ADR-0019 already names this), not by moving the field.

Q3 — Which autonomy rungs may a customer set themselves?

  1. Recommended. Customers move between Off / Suggest / Act with approval. Autonomous (anything that arms a send at a live property) is staff-set and customer-visible, greyed with "Ask PropFlow to enable". Keeps the one-field, one-card shape without handing customers an arm (Art. IV.6: activation is Fede's go). Org default applies to the parameters (spend ceiling), never to the rung — blast radius stays per property (VII.3).
  2. Customers set all four rungs. Rejected until a property has run a clean month on Act-with-approval.
  3. Customers set none; staff set everything. Rejected: it keeps 16 of 17 properties dark by default, which is exactly the failure hot rule 13 records.

Q4 — Where do prompts live?

  1. Recommended. Prompt text stays code (Art. VII.7; the ElevenLabs deploy lane is hard-blocked to merge-only). Per-property variation is data the prompt interpolates, and it already is ({{property_office_hours}}, {{pm_phone_number}}, {{property_policies}}, the hand-off directive). A customer never edits a variable as a variable; they edit the fact or setting that feeds it. The only new prompt-shaped customer fields worth adding are bounded and eval'd: a greeting line with a length cap and the fair-housing screen, and a tone selector from a fixed set — both on a Property "Clara" card, org default. Admin gets a read-only "what Clara is told about this property" rendering of the resolved variables, which the voice personalization route already computes.
  2. Customer-editable prompt text. Rejected: it bypasses evals and the deploy lane.

Q5 — Feature flags versus capabilities

  1. Recommended. Flags, arms and kill switches are Admin only, in the Access Inspector, catalogued in the arms registry (already enforced by a coverage test) — never on a customer page however nicely labelled. Capabilities are Organization, customer-facing, and they scope rather than arm: modules enabled, channels permitted, languages. Reviewer's rule of thumb: a capability off makes Clara do less; it can never make her send more. Consequence: the two toggles on /admin/settings today (SMS, vendor emails) are global kill switches wearing capability labels — they move to the arms tab, and module flags migrate from the platform-wide row to Organization.settings, which the type already declares.
  2. Keep customer-facing toggles that arm sends. Rejected: that is how the message-delivery PR shipped wording nobody decided on.

What never belongs on a settings page

Placement criteria — eight testable rules

From the taxonomy sweep; each rule names a PropFlow example, a counter-example, and what would falsify it.

Each rule is a question you can answer yes/no about a knob. Apply them in order; the first "yes" wins.

C1 — Whose fact is it? (level). If the value would be different for another person at the same company it is User; if it would be the same for every building the company runs it is Org; if another building of the same company could legitimately differ, it is Property; if no customer may ever see or change it, it is Admin. This is the Vercel account/team/project test and it is already CLAUDE.md's "whose fact is this?" (customer-facts-as-data).

**C2 — Does it change what a customer hears across channels? (settings page vs. elsewhere).** A knob that changes Clara's spoken/written behaviour on more than one channel (voice+SMS+email) is a setting and goes on the settings page for its level. A knob that only changes what an operator sees in a queue stays on the module page.

C3 — Is it a fact about the building, or a rule about behaviour? (property detail vs. settings). Facts (address, hours, amenities, fees, phone the public dials, unit count) live on the property detail page under "Policies & Knowledge" because Clara cites them and they need provenance (scraped vs. manual). Rules (how long a tour is, when to auto-approve) are settings. AppFolio/Buildium put late-fee policy on the property record for this reason; the product already split "collections policy" into cadence (setting) and late fee (knowledge) with a scope line (MoneyRulesSection.tsx header).

C4 — Is it only meaningful while looking at the work? (module page / drawer). If a PM would only ever change it with the queue in view (cadence while looking at 60-day-past-due accounts), it gets an edit-in-context drawer on the module page and a browse-and-compare row on the settings page — the same component, same API, never two stores. This is Intercom/Front's "rules live in the inbox" and Linear's team workflow settings; it is already the product's decided shape (PolicyDrawer.tsx header: "answered by construction rather than by picking one place").

C5 — Does it decide whether Clara acts or asks? (the Autonomy card). A knob whose only effect is who decides (Clara / Clara-then-approve / human) is a decider, not a policy, and every decider for a module sits together in one "Autonomy" card at Property level, read-only mirrored in the module. A threshold that feeds a decider (auto-approve $) is a decider parameter and sits in the same card.

C6 — Is the default the company's and the exception the building's? (inherit). A Property knob inherits from Org when (a) most buildings of one operator share the value and (b) an org-wide change should propagate to un-overridden buildings. Then the property card shows the effective value with an "Inherited from Organization" badge and a "Reset to organization default" action; an override is a stored value, absence is inheritance. Vercel env-vars-per-environment and Linear team-overrides-workspace are the model; resolvePreferredVendors is the in-repo precedent.

C7 — Can a customer be trusted with it without a soak? (Admin vs. Org "capabilities"). If flipping it needs the bench, a replay, or Fede's go (Art. IV.1, IV.6), it is Admin (Access Inspector arms/kill switches), never on a customer page, even a per-property one. If it is a product capability the customer bought or opted into (module on/off, a channel enabled), it is an Org "capabilities" toggle — customer-facing, but it scopes, it does not arm.

C8 — Is it a one-off action or a per-record field? (never settings). Connect/disconnect an inbox, import contacts, re-sync, delete property, "mark this tenant do-not-contact" are actions or record fields; they live where the record lives. A settings page holds standing values only.

What the codebase already says

Most of the "open" question is already decided in data — this is the evidence table the criteria were derived from.

FactWhere
Four levels shipped; names/routes in one filesrc/lib/domain/settings/settings-levels.ts
Property settings are two DDB rows: PROP#id / LEASING_SETTINGS and MAINTENANCE_SETTINGS, resolved property → hardcoded default, no org tier ("No global fallback. Operational settings live per-property only.")src/lib/platform/settings-resolver.ts, src/lib/data/types.ts:13060 (PropertyLeasingSettings), :13278 (PropertyMaintenanceSettings)
Organization.settings already declares an inheritance layer — "Cross-property defaults — overridable per-property where the per-property setting type allows it" — but has no writer and nothing reads ittypes.ts:12484 (OrganizationSettings), OrganizationSettings.tsx header (Company Name writes User.companyName)
Org-level preferred vendors with per-trade property override is the one working inheritance chain in the productOrganization.preferredVendors (ADR-0060), Property.preferredVendors "property-over-org … read only through resolvePreferredVendors" (types.ts Property block)
Follow-up cadences are org-scoped rows edited from a property context (the API derives the org from propertyId); the same editor is mounted in Settings AND in each module's PolicyDrawersrc/app/api/automations/cadences/route.ts header, src/components/domain/policy/PolicyDrawer.tsx, FollowupPolicyEditor.tsx:760-800, mounts in collections/CollectionsClient.tsx, leasing/renewals/board/_components/BoardV2.tsx, maintenance/work-orders/(list)/WorkOrderListClient.tsx, maintenance/turnovers/TurnoversClient.tsx, leasing/prospects/ProspectsClient.tsx
The one property-scoped rule inside a module drawer (collections late fee) carries an explicit scope line because it sits next to org-scoped cadencesrc/components/domain/policy/MoneyRulesSection.tsx header ("Applies to <name> only")
Every on/off gate is catalogued with family / polarity / control; UI at /admin/dev/access-inspector tabs modules, arms, rolessrc/lib/domain/admin/arms-registry.ts; src/app/(workspace)/(operations)/admin/dev/access-inspector
AppSettings is ONE global CONFIG/SETTINGS row carrying kill switches, module flags, a leaked subscription, and two UI prefs (setupGuideState, askClaraState)types.ts:13322, src/app/api/settings/route.ts header (the 2026-09-07 leak stopgap)
/admin/settings "Clara AI → SMS Messaging" and the two vendor-email toggles write that global row via POST /api/settings (platform-wide, despite the customer-sounding labels)admin/settings/page.tsx, _components/settings-sections.ts
The autonomy switch that exists is `Property.handoffMode: 'coworker' \'autonomous'` — ONE switch, on the property, script-only writer, drift-fencedtypes.ts Property block (handoffMode doc), src/lib/domain/escalation/handoff-mode.ts, scripts/set-handoff-mode.ts
Per-module graduation exists as data: `Property.capabilityStage.{leasing,renewals,maintenance}: off \shadow \live`types.ts Property block (G-1)
Renewal / collections / new-lease arms are a global script-written row, some with a propertyAllowlisttypes.ts:13390 (RenewalArmState), OperatingModeArmState :13635
Prompts are config-as-code: ONE fleet-wide voice prompt per agent, per-property variation only via dynamic variables ({{property_name}}, {{property_office_hours}}, {{pm_phone_number}}, {{property_policies}}, {{triage_greeting}}, the hand-off directive); deploy only on merge (hard-blocked)agents/clara/lib/voice-agents/*.ts, handoff-policy.ts header ("there is no prompt-override path"), agents/clara/lib/agent/clara-personality.ts, scripts/lib/elevenlabs-deploy-lane.ts
Building facts and structured policies live on the property detail page, not settings: office hours, holiday policy, pricing/fees, renewal policy (rent strategy, term options, MTM premium, voice-call), turnover policy (inspection timing, default trades/vendors, dispatch cost cap), vendor job reference mode, handymenPropertyKnowledge (types.tsofficeHours, holidayPolicy, pricingDetails, renewalPolicy, turnoverPolicy), properties/[id]/PropertyDetailClient.tsx (PricingDetailsEditor, TurnoverPolicyEditor, VendorJobReferenceCard, PropertyDetailsEditor)
Constitution: "One switch, on the property, or none … visible on the property's admin page" (IV.3); "configuration lives in data" (VII.1); "every customer has one kill switch" (VII.3); test/shadow/live on the record (VII.4); "Prompts, policies, and knowledge are code" (VII.7)docs/OPERATING-CONSTITUTION.md Art. IV, VII
Hot rule 13 / #4694: 16 of 17 properties sat dark behind per-property *Enabled opt-ins — the reason arms are now "halt" not "enable"types.ts (renewalLapseDigestEnabled doc, collectionsHalt doc), docs/runbooks/renewal-orchestration.md:44

The upshot: the product already has the shape of the answer — org default → property override for vendors, org-scoped policy edited in module context, one autonomy switch on the property, prompts as code with data variables. What is missing is (a) a general inheritance resolver (only vendors have one), (b) an Organization writer, and (c) a consistent rule for which surface shows what.

Applied table — about 95 knobs, current and proposed

Level: U/O/P/A. Surface: SP = settings page for that level · PD = property detail (Policies & Knowledge) · MP = module page (read-only mirror) · DR = drawer inside a module (edit-in-context, also browsable on the settings page) · AI = Admin Access Inspector. Inherits: O→P = org default, property override with badge and reset.

Level: U=User, O=Org, P=Property, A=Admin. Surface: SP=settings page for that level, PD=property detail (Policies & Knowledge), MP=module page (read-only mirror or filter), DR=drawer inside module (edit-in-context, also browsable on SP), AI=Admin Access Inspector. Inherits: O→P means org default, property override with badge+reset.

Clara voice & messaging

KnobLevelSurfaceInherits?RationaleExists today?
Company/brand name Clara signs asOSPC1 org identity; C2 every channelyes, but writes User.companyName (OrganizationSettings.tsx)
Clara display name at the PMS (pmsMessagingSync.claraDisplayName)PSP IntegrationsO→Pper-PMS-account identity; org defaultschema only (Property.pmsMessagingSync)
Greeting line (triage {{triage_greeting}})PSP Clara cardO→PC2 spoken on every call; templated text is a variable, not a promptvariable exists, value derived — no editor
Persona / tone (CLARA_CORE_PERSONALITY)AcodeVII.7 prompts are code; changing it is a replay-gated deployclara-personality.ts
Languages Clara will answer inOSP capabilitiesO→Pproduct capability; per-property override where a building is bilingualnot a knob; language is per-person on the spine (ADR-0089)
Business hours (office open/closed)PPDC3 building fact, scraped/manual with provenancePropertyKnowledge.officeHours (PropertyDetailClient.tsx:983)
Holiday closuresPPDO→P (federal default)C3 fact; org may standardisePropertyKnowledge.holidayPolicy
After-hours behaviour (take message vs. dial)Acodeone fleet policy by owner ruling; driven by hours datavoice-agents/after-hours-message-desk.ts
Transfer destination (office phone)PSP CallsC6 counter-example: physically per buildingyes Property.officePhone (PropertySettingsShell.tsx:237)
Emergency phonePSP Callssameyes Property.emergencyPhone
Vendor transfer-first on inboundPAutonomy carddecider; today an env armarms-registry.ts:465 (vendor.transferFirst, deploy-controlled)
Hand-off mode (coworker / autonomous)PAutonomy card (read-only until Fede flips)noArt. IV.3/IV.6 one switch, activation is Fede's; show it, don't let a PM write itProperty.handoffMode, script-only
Escalation owner + CC emailPSP NotificationsO→Pwho is paged; org default (ops inbox), property overrideProperty.escalationOwnerEmail/CcEmail (script-set)
SMS enabled (channel capability)OSP capabilitiesO→P (shadow)C7 customer capability, not an armglobal AppSettings.smsEnabled on /admin/settings (wrong level)
Email replies enabledOSP capabilitiesO→Psameglobal AppSettings.emailsEnabled
Shadow mode per channel (emailShadowMode, smsShadowMode)PAutonomy card, read-only; A writesVII.4 test/shadow/live is an activation stateProperty.emailShadowMode/smsShadowMode
Test property flagAAI (per property)behaviour switch that silences grading etc.; never customer-facingProperty.isTest
Clara's own numbers (Twilio)PSP Integrations (read-only list)routing fact; provisioned by staffProperty.twilioNumbers (absent everywhere; env map fallback)
Messaging delivery path (direct vs via PMS)PSP IntegrationsO→Pintegration postureProperty.messagingDelivery (schema)

Leasing

KnobLevelSurfaceInherits?RationaleExists today?
Tour durationPSP LeasingO→PGera's instinct is right: most operators run one length; building overridesyes tourDurationMinutes
Tour minimum lead timePSP LeasingO→Psame shapetourMinLeadMinutes (API, no UI)
Per-weekday booking policyPSP Leasingstaffing is per building (types.ts:13072)tourDayPolicy (API, no UI)
Tour buffers between slotsPSP LeasingO→Pnot builtno
Application linkPSP LeasingO→Pone portal per PMS account, per-property override for sub-portalsyes applicationLink
Pricing & availability sourcePSP Leasingwhich store is truthful is per building (scaffold rent rolls)yes leasingSource + resolvedLeasingSource
Qualification rules (income multiple, pets, screening)PPD PoliciesO→PC3: facts Clara cites; org standardisespartial in PropertyKnowledge.pricingDetails / lease policy
Post-tour follow-up delay + channelPSP LeasingO→Ppolicyyes
Prospect follow-up cadences (inquiry, re-engage, tour-confirm, post-tour)ODR on /leasing/prospects + SP Follow-upsO (P override not built)C4; API is org-scopedyes FollowupCadenceOverride
Account-wide contact ceilingOSP Follow-ups onlygoverns every laneyes TouchBudget
Escalated tour booking (Clara books when escalated)PAutonomy carddeciderProperty.escalatedTourBookingEnabled
Tour-request SMSPAutonomy cardsend armProperty.tourRequestSmsEnabled
Listing auto-publish on NTVPAutonomy cardsend armarms-registry.ts:198
New-lease pipeline (approved app → next-steps)P + AAutonomy card (P half); AI (global half)two-factor armRenewalArmState.newLeasePipelineSending + property flag
Rent-roll auto-syncPAutonomy carddecider on PMS writesProperty.autoSyncEnabled
Website listings sync URLPSP Integrationsfact about the building's siteProperty.publicListingsSync

Maintenance

KnobLevelSurfaceInherits?RationaleExists today?
Auto-approve threshold ($)PAutonomy cardO→Pdecider parameter; company spend policyyes aiAutoApproveThreshold
Turnover dispatch cost capPAutonomy card (same row, "also for turnovers")falls back to thresholdalready "one autonomous-spend ceiling, not two"turnoverPolicy.autoDispatchCostCap (PD today)
Emergency definitions (what counts as after-hours emergency)OSP Maintenance policyO→Plegal/insurance posture is company-wideno (issue types are code)
Vendor preferences by tradeODR on /vendors + SPO→P (built)the one working chainOrganization.preferredVendors/Property.preferredVendors
Handymen (in-house)PPD (roster)facts about who works this buildinghandymanVendorIds (Maintenance Automation card, expandable)
Maintenance tech phonePSP Notificationsper buildingyes
Handyman quiet hours— (per person)Vendor recordADR-0053: per-handyman, not per propertyVendorMembership.quietHours
Resident quiet hoursOSP Clara cardO→Pcompany posture; state law varies per propertycode default
Dispatch autonomy (Clara dispatches vs. asks)PAutonomy carddecidercapabilityStage.maintenance, vendor.dispatch arm
Vendor quote / dispatch emailsOSP capabilitiescapability, not an armglobal AppSettings.vendorQuoteEmails/vendorDispatchEmails on /admin/settings (wrong level)
Vendor chase cadencesODR on /maintenance/work-orders + SPOC4yes
Vendor job reference (WO vs PO)PPDO→PPMS convention per accountProperty.vendorJobReferenceMode (VendorJobReferenceCard)
Custom turnover task typesPPD / turnover moduleO→PtemplatesPropertyTurnoverSettings.customTaskTypes
Turnover policy (inspection delay/time, default trades, finishing trades)PDR on /maintenance/turnoversO→Prule, not fact → move out of knowledge (Risk 5)PropertyKnowledge.turnoverPolicy via PD TurnoverPolicyEditor
Photo deferral at intakeAAIbehaviour arm under soakarms-registry.ts:291

Renewals

KnobLevelSurfaceInherits?RationaleExists today?
Open window (days before lease end)PSP Leasing "Open renewal"O→Ppolicyyes renewalAutoStartDaysBeforeLeaseEnd
Rent strategy / max increase / term options / MTM premiumPDR on /leasing/renewalsO→Prules, currently in knowledge blob (Risk 5)PropertyKnowledge.renewalPolicy (RenewalsPolicyCard on PD + renewal detail)
Delinquency threshold for manual reviewPAutonomy card (renewals row)O→Pdecider parameterrenewalPolicy.delinquencyThresholdMonths
Voice call on offerPAutonomy cardO→Pchannel decisionrenewalPolicy.voiceCallEnabled
Autonomous sending / holdover conversion / auto-startAAI armsglobal script arms, Fede's callRenewalArmState
Workflow-owned dispatch allowlistAAIinfra cutoverworkflowOwnedDispatch
Renewal chase cadenceODR + SPOC4yes
Renewal contact email / phonePSP NotificationsO→Pwho is toldrenewalContactEmail/Phone (API, no UI)
Execution CC emails ("Lease signed")PSP NotificationsO→Paccounting team is usually org-wideyes
Leases-ending digestPSP NotificationsO→Ptemporary opt-in, remove per its own docrenewalLapseDigestEnabled (script)

Collections

KnobLevelSurfaceInherits?RationaleExists today?
Chase cadenceODR on /collections + SPOC4yes
Late fee / grace daysPDR extra (Money rules)O→Prule; today in knowledge with a scope linepricingDetails.lateFee via MoneyRulesSection
Tone (firm/friendly)ODRO→Pcopy variant; must be an eval'd variant, not free textno (copy is code)
Quiet hours (resident's clock)OSP Clara cardO→PADR-0129code
Enrollment threshold ($ / months)ODRO→Ppolicyconstants
Human approval before every sendAcode (ADR-0125)never a knob today; becomes the "act with approval" rung/review queue
Halt brakeAAIoperator stop, not a customer settingRenewalArmState.collectionsHalt
Eviction-firm / assistance correspondentsPPD Integrationscustomer identity factsProperty.collectionsCorrespondents, demandParty (script)
Owner escalation recipientPSP NotificationsO→Pwho is toldowner-escalation.ts

Conversations

KnobLevelSurfaceInherits?RationaleRationale / exists
Auto-reply on/off per channelPAutonomy cardO→P= capabilityStage per domaincapabilityStage
Human takeover rules (mute on staff reply, unmute on resolve)Acodeone fleet behaviourescalation/stale-mute-sweep.ts etc.
Signature / sender identityPSP IntegrationsO→PsendGridSenderIdentity per property; org default nameProperty.sendGridSenderIdentity
Operational senders to read-not-answerPPD Integrationscustomer identity factsoperationalDataSenders, appfolioTrustedSenders (script)
Topic labelling / gradingAAI runtime switchesobservabilityruntime.* arms

Notifications (who is told what)

KnobLevelSurfaceInherits?RationaleExists
PM action reminders on/off, count, intervalPSP NotificationsO→PADR-0104; company cadenceyes pmActionReminders
Property inbox (propertyEmail)PSP IntegrationsfactProperty.propertyEmail
Weekly owner report recipients + windowPSP NotificationsO→Powners are per building; window is org habityes
My notification preferences (digest vs. each)USP UserC1no
Slack/ops channel for holdsAAIPropFlow opsenv

Integrations

KnobLevelSurfaceInherits?RationaleExists
AppFolio / PMS credentials, subdomainOSP Integrationsone database per org (two DBs = two orgs)yes (OrganizationSettingsShell.tsx:313)
PMS account binding per propertyPSP Integrations (read-only)which DB this building lives inProperty.pmsAppfolioAccount
Outlook calendar / inboxPSP Integrationsproperty-keyed today; org connection is Fede's future seamyes
Hidden-from-sync propertiesU → should be OSP Orgtoday User.ignoredPropertyIds — a per-user denylist governing org sync (Risk 6)OrganizationSettings.tsx
Twilio number provisioningAAIstaffenv map

Security / team

KnobLevelSurfaceInherits?RationaleExists
Team members, invites, rolesOSP TeamLinear/Vercel membersyes
Assigned properties per userOSP Team rowscopeUser.assignedPropertyIds
Role → tab permission matrixAAI rolesplatform policy ("hierarchy governs invites only, never Clara capabilities")/api/admin/permissions
MFA / SSO / sessionsO (policy) + U (enrol)SPorg mandates, user enrolsno
Impersonation auditAAIstaffADR-0019

Billing / plan

KnobLevelSurfaceInherits?Exists
Plan, unit count, invoices, cardOSP Billingyes (/api/billing/status)
Sandbox / purposeAAIOrganization.isSandbox, purpose

Admin / platform

KnobLevelSurfaceExists
Module flags (enabledModules)A today → O capabilityAI modulesplatform-wide row (/api/admin/modules header says org-scoping "is a separate migration")
Kill switches (kill.*) with per-property false overrideAAI armstour-pipeline-flag.ts
Two-factor send arms, global env armsAAI arms / deployarms-registry.ts
Staged cutovers (tour.deciderMode)Adeploytour-decider-flag.ts
Test phonesAAIAppSettings.testPhones
Eval/bench toggles, trace captureAAI runtimeruntime.*
Escalation holds (bake gate)A/admin/escalation-holdsescalationBakeApprovalRequired
User UI state (setupGuideState, askClaraState)U, not Anot settings at allon the global CONFIG/SETTINGS row today (Risk 6)

Row count: ~95.

The recommended model in detail

(a) Inheritance chain and display

Chain: platform default (code constant) → Organization → Property. No unit or user tier for behaviour knobs — a unit-level exception is a fact on the unit record (C3), and a user-level one is a preference (C1), never a Clara behaviour. This matches today's vendors chain and settings-resolver.ts's "property → hardcoded default", with one new middle rung.

Mechanics, so the resolver stays one function:

(a2) The company decides WHICH keys a building may override — so the resolver must return permission, not only value

Added 2026-09-09, from the founders’ thread. Fede: “right now the policies are on the property level… I don’t know if you want to rip that out and make it its own thing on the nav or nested under Clara… where you could visualize the global settings and then be able to visualize property.” Gera’s answer to the second half: an overridable key at property level shows “a little green indicator that it’s allowed to override by property firm” and is editable; a non-overridable one renders greyed.

That is not a styling note. It changes the read path. { value, source } answers “what is in force and where did it come from”; it cannot answer “may I write this here?” — and the screen has to answer that before it can decide whether to render a control or a lock. The management firm is the rule book: it sets quiet hours, pet fees and policies, and which of those a building may depart from. So:

Unresolved between Gera and Fede — shown coming-soon, not settled. Gera wants a locked field to offer “click here to message the firm” through PropFlow. Fede, same thread: “I wouldn’t over complicate… we’re dealing with small clients, that would be more of an enterprise solution… I don’t think it’s necessary to build a lot right now.” Both are reasonable and it is their call, not this page’s: a request channel is real work (a thread, a notification, a state machine per request) and the same need is served on day one by the building manager phoning whoever set the rule. The affordance appears on the wireframes greyed, and stays greyed until one of them decides. The architecture side has since proposed a middle path worth having: make it a capability that renders only when the person holds it, so the contract exists and the control is simply absent for everyone else. That is Fede’s “don’t build much” and Gera’s “don’t let them get stuck” in one shape. It also forces a distinction this page should keep: not built yet and built but not granted to you are different states and must not render alike — the first is the ⓘ greyed row, the second is simply not there.
On Fede’s nav question, this page’s existing answer: policies do not get ripped out to their own nav item, and they do not nest under Clara. They stay on Property Settings, because the test that put them there still holds — would this still need to be true if you cancelled PropFlow tomorrow? A pet fee is a fact about the building and lives on the building page; “how Clara handles a pet question” is an instruction to the software and lives in Settings. What Fede is actually missing is the other half of his sentence — seeing the global and the property view together — and that is the Organization level plus the inheritance badge, not a new nav item. A separate “Policies” tab would split one subject across two places and re-create the drift this page exists to remove. Nesting under Clara is worse: it implies the policy is Clara’s rather than the company’s, and the company’s policy outlives any agent.

(b) Deciders — argue for one Autonomy card per module at Property, with two amendments

The instinct is right and the constitution forces it: IV.3 wants exactly one per-property switch, visible on the property's admin page, and VII.4 wants test/shadow/live on the record. The codebase is already converging: handoffMode (one switch), capabilityStage (per-module off/shadow/live), aiAutoApproveThreshold + autoDispatchCostCap (one spend ceiling).

Recommended shape — one "Autonomy" card on Property Settings, one row per module (Leasing, Tours, Maintenance, Renewals, Collections, Conversations), each row = a 4-step ladder Off / Suggest / Act with approval / Autonomous plus that module's decider parameters (spend ceiling, delinquency threshold, voice-call-on-offer). Mirror: a read-only "Clara here is: Act with approval" pill in each module page header that links to the card (C4: read-only mirror, never a second writer — the two-place problem Gera named).

Amendments that matter:

  1. Not every rung is customer-writable. "Autonomous" (and any rung that arms a send at a live property) is Fede's activation (IV.6). The card shows the current rung to the customer; the write for Off↔Suggest↔Act-with-approval is a customer action; Autonomous is staff-only and greyed with "Ask PropFlow to enable". That preserves the one-switch rule (one field, one card) without handing customers an arm.
  2. Map the ladder onto what exists instead of inventing a new field. Off = capabilityStage: 'off'; Suggest = 'shadow'; Act with approval = 'live' + review-queue gating (ADR-0125 collections, vendor outreach first-dial); Autonomous = 'live' + handoffMode: 'autonomous' / the module's send arm. Today's scattered booleans (escalatedTourBookingEnabled, tourRequestSmsEnabled, autoSyncEnabled) become rows of this ladder or collapse into it.
  3. Org default: only for the parameters, not the rung. Spend ceiling inherits; the rung does not (VII.3 "blast radius is per property").

Against a per-module page card as the writer: it would put an arm next to a queue where a PM toggles under pressure, and it re-creates the "two places" problem. Against a settings-only card with no mirror: the review queue's "why is this here?" already needed inline copy (review/page.tsx header) — the mirror answers that.

(c) Prompts

(d) Feature flags vs. capabilities

(e) What never belongs on a settings page

  1. Facts about the building — hours, amenities, fees, utilities, neighbourhood, phone the public dials (detail page, with provenance).
  2. Per-record fields — a tenant's language, do-not-contact, a vendor's quiet hours (VendorMembership.quietHours), a unit's availability.
  3. One-off actions — import, re-sync, delete, backfill, "send now".
  4. Arms and kill switches (Admin only).
  5. UI state — setupGuideState, askClaraState, dashboard layout (per-user prefs, stored on the user, no page).
  6. Anything with no reader: the "manual" leasing source is offered disabled for exactly this reason (leasing-settings/route.ts); the rule generalises — a setting ships only with its consumer (hot rule 13).

What is mis-scoped today — the inventory's observations

From the inventory sweep of the four settings pages, the property detail page, every module drawer, the arms registry, env-only knobs and the data model. File and line references are in the sweep and were read at ad990d3cb5.

Added 2026-09-08 — a personal preference stored per building. “Reminders for you” (whether to be reminded about pending approvals, how many, how often) is pmActionReminders on the property’s leasing settings. It is the one thing on the settings surface that is about a person but keyed to a building: twelve buildings means twelve copies of one manager’s preference, and no Account-level default for them to inherit from.

  1. Company Name is an org fact stored per user (User.companyName, OrganizationSettingsShell.tsx:172; OrganizationSettings.tsx:15-18). Organization.settings and Organization.name have no writer in src/app.
  2. "Hide from sync" is an org-wide destructive action keyed on a per-user denylist (User.ignoredPropertyIds, ignored-properties/route.ts:149) — another user still sees the property until sync re-imports it; deletion is real.
  3. Admin Settings toggles are one global row for every org (CONFIG/SETTINGS; api/settings/route.ts:26-33), was writable by any requireUser caller (:183) — closed by #7365, staff-only on write; the page calls them "user-level" (admin/settings/page.tsx:15). OrganizationSettings type duplicates the same fields (types.ts:12484-12496) and is dead.
  4. AppSettings.smsEnabled is not read by the SMS transport — the real per-property gate is Property.smsShadowMode (script-only) (types.ts:3082-3083). Global emailShadowMode defaults to true (dynamo/settings.ts:30) and per-property Property.emailShadowMode is PATCH-able but has no UI.
  5. Follow-up cadences and contact limits are ORG-scoped but only editable from a property context (PK=FOLLOWUP#<orgId>; drawer + Settings card require propertyId; PolicyDrawer.tsx:60-75 explains the tension). Editing "Past-due balance" on Camellia rewrites it for every property in the org.
  6. Late fee / grace days have two write paths — property page Pricing editor and the Collections policy drawer — both on PropertyKnowledge.pricingDetails, with a documented clobber hazard (MoneyRulesSection.tsx:16-22).
  7. Two "office phone" fields with different meanings on two pages: Property.officePhone (transfer destination, Property Settings) vs PropertyKnowledge.phone (public line, property detail page); Property Settings seeds one from the other (PropertySettings.tsx:98).
  8. Renewal autonomy switch lives in three places: RenewalPolicyEditor (autonomousRenewalEnabled), the Arms tab (same flag), and the global CONFIG/RENEWAL_ARMS row (script only). The "Open renewal N days" setting in Property Settings does nothing unless the global autoStart arm is on — not surfaced there.
  9. ~35 per-property behaviour switches have no UI at all (§4b) — including the single most important one, handoffMode, plus timezone, smsConsentMode, escalation owner, shadow modes, tour day/lead rules, PM notification mode, holiday closures, lease policy. Each has its own scripts/set-*.ts or a hand DDB write.
  10. Leasing-settings route accepts fields the page never shows (tourMinLeadMinutes, tourDayPolicy, postTourFollowUpChannel, deprecated renewalOutreach*leasing-settings/route.ts:75-93,226-235); turnover-settings route has no UI caller.
  11. Global UI prefs stored globally: setupGuideState and askClaraState are on the shared CONFIG/SETTINGS row, so one user's collapse affects everyone (types.ts:13377-13383).
  12. Per-property kill-switch overrides (PropertyLeasingSettings.turnIntegrity*/tour*Enabled) exist but the Arms tab only writes the global half.
  13. Env arms that need a deploy (leasing digest, vendor dispatch, tour chokepoint, preference capture, stated-name, tour window, voice callback, decider mode, NTV routing) are global across customers; the two-factor design means the per-property flag is the only per-customer control and it is Arms-tab/script only.
  14. Customer facts still in source/env: Twilio numbers with hardcoded fallbacks (phone-lookup.ts), ElevenLabs agent ids, recipient allowlists (VENDOR_DISPATCH_RECIPIENT_ALLOWLIST, LEASING_REPORTING_DIGEST_REVIEW_RECIPIENT, BAKE_ALERT_EMAIL), TEST_PROPERTY_TRANSFER_TARGET.
  15. Retired env names linger in tests only: MAINTENANCE_AUTONOMOUS_SENDING, PM_ACTION_REMINDERS_ALLOWLIST, MAINTENANCE_HANDYMAN_QUIET_HOURS_DISABLED, RENEWAL_AUTO_START_ENABLED (8 non-test reads remain for the last one).
  16. Handyman quiet hours are per vendor-membership, default ON, script-only (set-handyman-quiet-hours.ts); tenant quiet hours are hardcoded TCPA on Property.timezone, which itself has no UI and silently defaults to Chicago.
  17. Turnover policy editor edits 2 of 7 fields on PropertyKnowledge.turnoverPolicy (timing fields unreachable), while the Turnovers page drawer only carries follow-up cadence.
  18. **Dashboard/user prefs sit under /api/settings/* (dashboard-layout, dashboard-card-windows) next to the global admin route — same URL family, three different scopes (user / global / user).

Per-property behaviour switches with no UI

Each of these is a customer-relevant behaviour today changed only by a script or a hand write to DynamoDB. The applied table above says where each belongs.

FieldWhat it doesWriterCite
`Property.handoffMode: 'coworker'\'autonomous'`THE per-property "how Clara behaves when she needs a human"scripts/set-handoff-mode.tstypes.ts:3206-3246
Property.escalationCoworkerModeEnabledescalation coworker modeset-escalation-coworker-mode.ts:3204
Property.escalatedTourBookingEnabledbook tours on escalated threadsset-escalated-tour-booking.ts:3167
Property.escalationOwnerEmail, escalationOwnerCcEmailwho owns decision requestshand DDB write (no script named):3000-3016
Property.escalationBakeApprovalRequiredtemporary bake gate (hold team emails for Slack approval)hand DDB write:3018-3052
Property.escalationRelayRephraseEnabledrelay staff answers in Clara's wordsnone found:3722
Property.emailShadowMode, smsShadowModeprocess but don't sendPATCH route accepts emailShadowMode (no UI); set-property-sms-shadow-mode.ts:3062, 3075
Property.tourRequestSmsEnabledtext-back after un-bookable tour asknone found:3114
Property.publicListingsSync{url,mode}portfolio-line listings scrapehand write:3136
`Property.messagingDelivery: 'direct'\'pms'`which door messages leave byset-messaging-delivery.ts (PATCH also accepts):3691
Property.pmsMessagingSync{enabled,…}import AppFolio guest-card threadsset-pms-messaging-sync.ts:3536
Property.pmsAppfolioAccount{accountId,appfolioSubdomain}which AF databaseset-appfolio-account.ts:3637
Property.appfolioTrustedSenders[], operationalDataSenders[], inboundEmailAddresses[], twilioNumbers[]routing/security listsset-appfolio-trusted-senders.ts, set-operational-data-senders.ts, set-property-inbound-email-addresses.ts, set-property-twilio-numbers.ts:3435, 3306, 2976, 2934
Property.collectionsCorrespondents, demandPartycollections counterparties / who the demand is fromset-collections-correspondents.ts, set-demand-party.ts:3343, 3375
Property.timezoneTCPA quiet-hours zone (defaults America/Chicago)none found:3772
Property.smsConsentMode, jurisdictionStateCode, capabilityStage{leasing,renewals,maintenance: off/shadow/live}, autoSyncEnabled, pmsSource, operatingMode, sendGridSenderIdentity, isTestconsent model; legal module; per-domain graduation; rent-roll auto-apply; PMS wiring; sender identity; test behaviour switchmostly none (PATCH accepts capabilityStage; PMS inspector displays some):3794, 3799, 3440, 3445, 3451, 3470, 3067, 3059
Property.autoDraftLeaseOnApprovalEnabled, newLeaseTemplateName, promiseLedgerCallerOutboundEnabled, transferMissedOutreachEnabled, topicScopedHoldUnmuteEnabledlease auto-draft; AF template; promise-kept texts; missed-transfer paging; topic-scoped holdset-auto-draft-flag.ts, none, set-promise-caller-outbound.ts, set-transfer-missed-outreach.ts, set-topic-scoped-hold-unmute.ts:3867, 3891, 4013, 4063, 4115
PropertyLeasingSettings.tourMinLeadMinutes, tourDayPolicy{allowSameDay,minLeadMinutes} per weekday, renewalContactEmail/Phone, renewalLapseDigestEnabled, ownerReportWindowDays, `pmNotificationMode: all\outcomes_only, leasingActivityChannel/Mention, postTourFollowUpChannel`tour booking rules; PM escalation contacts; lapse digest; owner window; PM notification volume; Slack channel; follow-up channelroute accepts tourMinLead/tourDayPolicy (leasing-settings/route.ts:75-93) but no UI; set-property-lapse-digest.ts; set-pm-notification-mode.ts; set-leasing-activity-mention.tstypes.ts:13070-13079, 13105-13108, 13138, 13157, 13269, 13243-13250
PropertyKnowledge.holidayPolicy{observeFederalHolidays,openOn,extraClosures}, freeMonthAppliesTo, leasePolicy (ApplicationLeasePolicy: terms, deposit tiers, app fee)tour holidays; special mechanics; lease termsnone / set-free-month-applies-to.ts / none (lease-terms/policy-store.ts:4-8)types.ts:4418-4434
PROP#/CONFIRMATION_REVIEW_RECIPIENT {name, phone}, PROP#/ONSITE_PRICING {propertyCode, baseUrl, enabled}who reviews confirmations; On-Site scrapenone founddynamo/settings.ts:212-227, 159-176; types.ts:2545, 4324
emailIntegration.teamMonitoredInboxmailbox the team also readsset-team-monitored-inbox.ts
Per-role permission overrideswhich roles may do which actionsAccess Inspector Roles tab → /api/admin/permissionsPermissionOverride (types.ts:13957)

Open questions for the founders — each with a recommendation

  1. Org level has no writer. Organization rows cannot be edited; Company Name writes User.companyName; follow-up cadences are org-scoped but need a propertyId to derive the org (cadences/route.ts), so the Org-level Follow-ups card is shaky when "All Properties" is picked (FollowUpsCard takes propertyId: string | null). Recommend: Fede's "add a customer" back-office flow lands the writer first; until then no O→P inheritance can ship, so sequence it before the Autonomy card.
  1. Gera's org-level list is right for two of three. Tour duration and application link → O→P (C6). Transfer destination → Property-only; the "org" feeling comes from single-property customers, where the two levels collapse — handle with the "single-property org hides the property/org split" refinement ADR-0019 N2 already names, not by moving the field.
  1. Should customers ever write "Autonomous"? Constitution says no (IV.6). Recommend: customer-writable rungs stop at "Act with approval"; Autonomous is staff-set, customer-visible. Revisit once a property has run a clean month.
  1. enabledModules and the /admin/settings toggles are platform-wide but read like customer settings. One org flipping them flips every org. Recommend: migrate to Organization.settings (type already declares them) in the same PR that adds the org writer; delete the toggles from /admin/settings, leaving it as a pointer page to the Access Inspector.
  1. Rules are stored inside PropertyKnowledge (renewalPolicy, turnoverPolicy, lateFee) — the knowledge route's sanitizer clobbers siblings on partial PATCH (MoneyRulesSection.tsx "CLOBBER NOTE"). Recommend: new rule fields go to PropertyLeasingSettings/PropertyMaintenanceSettings; move the three existing ones when their drawers ship, with the same single-home drift test used for lease policy (lease-policy-single-home.drift.test.ts).
  1. Wrong-level state already in the tables: User.ignoredPropertyIds governs org sync; setupGuideState/askClaraState live on the global config row; subscription and legacy company fields on the shared row (the 2026-09-07 stopgap in api/settings/route.ts). Recommend: a one-time "level audit" ratchet test — every field on AppSettings must be declared platform-wide by a comment or fail — and move the three named fields.
  1. Time zone: todayDenver() hardcodes America/Denver for every prompt (clara-personality.ts), while the user setting says "Times show on each property's clock". Not a settings-page question, but the first out-of-Colorado customer breaks on it. Recommend: property timezone becomes a required building fact on the detail page and the prompt helper reads it.
  1. Inheritance vs. hot rule 13. An org default that is absent must never leave a property dark. Recommend: the resolver's third rung is always a code default (never "off"), and the falsifier for every inherited knob is a test that an empty org row reproduces today's per-property behaviour byte-for-byte — the same "UNSET = today's behavior" contract every recent property field already documents.

Bottom-up: what is hard-coded to one customer today, and where it becomes a setting

Gera, 2026-09-08: "a lot of things are kind of hard-coded to Camellia or even JPCO; now that we're onboarding new organizations and properties, all that stuff needs to be at the right settings page, configurable and clear." This section works from the code upward. Sources: the customer-identifier fence's own ledger of known violations (customer-identifier-fence.drift.test.ts, categories B and C are the live coupling), a sweep for customer names, subdomains and time zones across src/lib, src/app/api, agents and lambda, and the inventory's env-only knobs. Prompt examples that merely mention a customer ("tour confirmed at Camellia Apartments") are hygiene, not settings, and are listed last.

Hard-coded todayWhereWhat it really isBecomesLevel · surfaceField exists?
Phone → property routing table with two customers' property ids, plus TWILIO_NUMBER_* env fallbackssrc/lib/domain/properties/phone-lookup.tsWhich numbers belong to which buildingThe property's inbound numbers, read at runtimeProperty · Integrations (staff-provisioned, read-only row)Property.twilioNumbers exists, set nowhere
Test-property transfer targetenv TEST_PROPERTY_TRANSFER_TARGETWhere an unknown caller on the bench property is sentThe bench property's own transfer destinationProperty · Calls (already the card for real properties)Property.officePhone — use it for the bench too
Prompt clock: America/Denver in ~15 places (todayDenver, PROMPT_TIME_ZONE, FLEET_DISPLAY_TIME_ZONE, tour date resolution, email extractors, post-transfer); TCPA quiet hours default to America/Chicagoagents/clara/lib/agent/clara-personality.ts, context-message-filter.ts, tools-leasing.ts, email/extract-tour-*.ts, voice/post-transfer.ts, format.ts; Property.timezone defaultA fact about the buildingOne required property time zone, set at onboarding; every prompt helper reads it (no fleet default)Property · detail page (building fact), with an Organization default for single-market operatorsProperty.timezone exists, no UI, silently defaults
Listings sync pinned to one property id and one AppFolio subdomain (LISTINGS_CONFIG)src/lib/domain/leasing/listings-sync.tsWhere a building's public listings livePer-property listings source URL + modeProperty · IntegrationsProperty.publicListingsSync exists (hand-written)
Properties that ingest rent rolls via the Data API — a hard-coded id listagents/clara/lib/email/process-inbound-email.tsWhich store is truthful for this building's rent rollPer-property rent-roll sourceProperty · Leasing (next to Pricing & availability source)Property.rentRollSource accepted by PATCH, no UI
AppFolio base URL jpco.appfolio.com in the browser agentlambda/agent-runtime/vendors/appfolio/apiClient.tsWhich AppFolio database this building lives in (two databases since 2026-09-01)Account subdomain threaded from the property's PMS bindingOrganization · Integrations (credentials + database) and Property · Integrations (which account, read-only)Property.pmsAppfolioAccount exists (script-set); Org AppFolio card exists
The management company's street address inside a shared voice promptagents/clara/lib/voice-agents/vendor-outbound.tsA company fact Clara reads out to vendorsA prompt variable fed from the organization recordOrganization · Company card (name, address, phone)No — Organization has no writer at all today
Company name Clara signs asUser.companyName via PATCH /api/auth/meA company factOrganization.nameOrganization · Company cardWrong level today (per user)
Vendor mail domains / vendor names to skip when loading costs (SKIP_DOMAINS, VENDOR_NAMES)src/lib/domain/maintenance/load-cost-data-core.tsOne operator's vendor rosterThe organization's vendor directory and operational sendersOrganization · Vendors page (exists) + Property · Integrations "senders to read, not answer"Organization.preferredVendors exists; Property.operationalDataSenders exists (script-set)
Per-property scraper modules carrying the property id and public web domainsrc/lib/platform/scrapers/camellia.ts, yale25.tsWhere the building's website is and how to read itWebsite URL on the property record; scraper config as dataProperty · detail page (Website URL exists) + Admin for the scraper recipePropertyKnowledge.websiteUrl exists
Known property names and aliases for email classification (KNOWN_PROPERTIES)agents/clara/lib/email/classify.tsWhat people call the buildingAliases on the property record, derived list at runtimeProperty · detail page ("Also known as")No field — new
A prod property id named in order to REFUSE it (FORBIDDEN_PROPERTY_ID)src/app/api/canary/suppression-probe/route.ts"Is this a real customer?"The property's test flagAdmin · Access Inspector (per property)Property.isTest exists
Recipient lists and staff addresses in env: VENDOR_DISPATCH_RECIPIENT_ALLOWLIST, LEASING_REPORTING_DIGEST_REVIEW_RECIPIENT, BAKE_ALERT_EMAIL, ADMIN_EMAILSdeploy envWho gets which email at which companyNotification recipients on the property / organization; staff lists stay AdminProperty · Notifications (owner report, lease signed, escalation owner) · Admin for PropFlow-internal alertsPartly: escalationOwnerEmail, ownerReportRecipients, renewalExecutionCcEmails exist
ElevenLabs agent ids as constants; one agent set for every customeragents/clara/lib/voice-agents/*.ts, *.config.jsonWhich voice agents answer for which accountPer-organization agent mapping in data, prompts still codeAdmin · Access Inspector (staff-provisioned per org)No — new
Escalation owner / CC, collections correspondents, demand party, trusted senders, inbound addresses — all script-writtenscripts/set-*.ts → Property fieldsCompany and building identity facts Clara relies onThe same fields, with a home on the settings pagesProperty · Notifications (owner/CC) · Property · Integrations (senders, correspondents, inbound addresses)Fields exist; no UI
Customer names inside prompt examples and tool descriptions ("tour confirmed at Camellia Apartments", "e.g. Yale 25")clara-leasing.ts, tools-leasing.ts, tools-comms.ts, spam-fewshot.tsWorked examples, not routingPlaceholders ({{property_name}}, "Example Apartments")Code hygiene, not a setting

Onboarding-ready checklist: what a new organization and a new property must have before Clara runs

The same list read the other way: the fields a customer (or staff, at onboarding) sets, at which level, and whether the product can take the value today. "No UI" means the field exists and only a script writes it; "hard-coded" means the code does not read a field at all. This is the working spec for the settings pages: every row is a field or a card.

Organization — set once per customer

FieldWhy Clara needs itCardToday
Company name, address, main phoneSignature on every email; what vendors are told; the voice prompt's "who we are"CompanyName per-user; address hard-coded in a prompt; phone absent
First company admin (invite), then the team with rolesWho may manage the company's settings and peopleTeamInvite exists; admin-level management shipping in the team-management PR
PMS: AppFolio database subdomain + API credentialsEvery sync and every write-backIntegrations · AppFolioExists
Plan and billingUnit count, invoicesBillingExists
Capabilities: modules on, channels permitted (SMS, email), languagesScopes what Clara may do for this company — never arms a sendCapabilities (new)Platform-wide global row today, admin-only
Company defaults that properties inherit: tour duration, application link, PM reminder cadence, auto-approve ceiling, follow-up cadences, contact ceilingMost operators run one policy; buildings overrideDefaults (new, once the resolver exists)Property-only today; cadences org-scoped but edited from a property
Preferred vendors by tradeDispatch and quotesVendors page (exists)Exists — the one working inheritance chain
Which properties to sync / hidePortfolio scopeProperty syncKeyed on a per-user list today; must move to the organization

Property — set once per building

FieldWhy Clara needs itCardToday
Name, address, aliases, time zoneHow Clara names the building; every date and every quiet-hours windowProperty detail (building facts)Name/address exist; aliases hard-coded; time zone no UI and defaulted
PMS account binding (which AppFolio database), rent-roll source, pricing & availability sourceWhich store is truthfulIntegrations / LeasingBinding script-set; rent-roll source no UI; pricing source exists
Inbound numbers (Twilio), property inbox and inbound addresses, sender identityRouting every call, text and email to this buildingIntegrations (staff-provisioned, read-only)Numbers hard-coded; inbox exists; addresses script-set; sender identity script-set
Office phone (transfer destination), emergency phone"Get me a human"; after-hours emergenciesCallsExists
Office hours, holiday closures, website URLTour availability, "are you open", what to scrapeProperty detailHours and website exist; holidays no UI
Outlook calendar and inbox connectionBooking tours; reading the property inboxIntegrationsExists
Tour duration, minimum lead time, per-weekday policy, application link, post-tour follow-upWhat Clara offers and sendsLeasing & toursDuration, link, delay exist; lead time and weekday policy no UI
Escalation owner + CC, maintenance tech phone, owner-report recipients, lease-signed CC, PM remindersWho is told whatNotificationsTech phone, recipients, CCs, reminders exist; escalation owner script-set
Auto-approve ceiling, handymen, preferred-vendor overrides, turnover policyMaintenance decisions and dispatchAutonomy (ceiling) · Vendors page · Turnovers drawerCeiling and handymen exist; turnover policy 2 of 7 fields editable
Renewal window and offer rules; late fee and grace days; collections correspondentsRenewals and collections behaviourLeasing (window) · Renewals drawer · Collections drawer · Integrations (correspondents)Window exists; rules live in the knowledge blob; correspondents script-set
Per-module autonomy rung (Off / Suggest / Act with approval / Autonomous) and shadow state; test flagWhether Clara acts or asks, and whether this is a real customerAutonomy card (customer-visible; the top rung staff-set) · Admin for the test flagcapabilityStage, handoffMode, shadow modes, isTest all exist — none has a UI

Admin — PropFlow staff only

FieldWhyToday
Voice agent mapping per organization; Twilio number provisioning; scraper recipesInfrastructure a customer never touchesAgent ids are constants; numbers in env; scrapers are modules
Arms, kill switches, staged cutovers, eval and trace togglesSoak-gated behaviourAccess Inspector (exists)
Staff alert recipientsPropFlow's own opsenv

Sequencing — what has to land first

  1. An Organization writer. Nothing at the org level can be edited today: Company Name writes User.companyName, follow-up cadences are org-scoped but need a propertyId to find the org. Fede's "add a customer" back-office flow is that writer; until it exists no org→property inheritance can ship, so it goes before the Autonomy card. Team management (add/remove people with roles from Organization Settings) is the first customer-facing org-level write and can land alongside it.
  2. The settings resolverresolvePropertySetting(propertyId, key) returning value + source, replacing the "property → hardcoded default" resolver; its contract test is that an empty org row reproduces today's per-property behaviour byte for byte.
  3. The Autonomy card on Property Settings with the read-only module mirrors, mapping the ladder onto capabilityStage / handoffMode / the send arms, and folding today's scattered booleans into rows.
  4. Move the wrong-level state: the /admin/settings toggles to the arms tab; enabledModules to Organization.settings; setup-guide and Ask Clara state to the user; hidden-from-sync from the user denylist to the org. A ratchet test that every field on the global config row is declared platform-wide by a comment, or fails.
  5. Give the 35 no-UI switches a home per the applied table — most become rows of the Autonomy card or the Notifications card; identity lists (trusted senders, correspondents, Twilio numbers) become read-only Integrations rows staff provision.

Method: two read-only research passes over the repository (an inventory pass and a placement pass), synthesised here. Product comparisons drawn on: Vercel account/team/project, Linear workspace/team/personal, Intercom and Front (inbox rules live in the inbox), Stripe, AppFolio and Buildium (company policy templates with property-record overrides). Related: the four-level split (#7324), one shell per level (#7326).

PropFlow Docs