sendLeads, thread notes via updateLeads, work orders via sendWorkOrders) is design-only until Brent signs off writes for that specific property in writing. Reads are unaffected, availability, pricing, leads, move-in dates, lease data, work orders and consent state all pull normally, so the data architecture in section 8 is live as written. Deferred, not cancelled: the design intent below stands, and in the interim every touch logs to the local outbox and replays into Entrata once writes are approved for that property. Deferring the write isn't permission to skip the logging, it only changes where it lands for now, and the local record has to be complete enough to replay. Two write services are live on the key (sendLeads and updateLeads). Maintenance is a READ surface now, not a write one: Liberty put the whole maintenance group on the key on 2026-08-03 and getWorkOrders + getWorkOrderPickLists are verified returning production data, but sendWorkOrders and updateWorkOrders were withheld in that same grant, so their absence is a deliberate per-method state, and a reachable maintenance surface is a reason to be more careful, not less. Brent declined to have the two writes removed on 2026-07-31, so assume write capability is permanently present and there is no vendor-side guard by choice. Our own deny-by-default read-method allowlist, enforced at the one function that issues requests and failing safe, is the only control that ever prevents a write. Rule 12 rides at the same choke point: never ingest, persist or log an SSN, and store birthdays as month and day only.1. Where guests come in, and who answers
All text-based contact goes to the Foothold AI agent (one brain across web form, chatbot, email, SMS). Live phone calls forward to LAG.
→ Foothold AI agent (ownership)
- Apartments.com / Zillow inquiries (lead email routed to agent)
- footholdboise.com/[property] inquiry form
- Website chatbot (same agent)
- Email to the ownership address
- SMS to the ownership number
→ Liberty / LAG (operations)
- All live phone calls (sales or service) forward to LAG, a human answers
- Listing maintenance (Apartments.com / Zillow, in Entrata)
- All service / maintenance / rent / lease contact
2. The sequence
Left to right is time. The red line is the handoff. Entrata is the record underneath the whole thing; GHL (ownership's marketing brain) gets fed in parallel.
(AI agent)
(Entrata)
(the record)
sendLeadsBLOCKED (rule 2), queues to outbox
updateLeadsBLOCKED (rule 2), queues to outbox
our writes BLOCKED, queue to outbox
sendLeads only hard-requires the property ID, but a card with no way to reach them is garbage. The legacy ILS/MITS feed also wants a last name.) Until then the chat lives in NPI's stack only. Rule 2: sendLeads is a write, so today the card queues in the outbox instead of reaching Entrata. The gate still governs, it decides what we're allowed to queue.getMarketingPreferences returns per-customer optIn by channel (email, phone, postal_mail, sms) with a consent type, and it is a precondition on the send path, not a courtesy. Read consent before an outbound touch, never infer it from having an address or a phone number, and treat a missing preference as "don't send" rather than "no objection." Postal mail is a first-class consent channel, which matters here because most of the recognition engine in section 4 is physical mail. ⚠️ The same customer can hold BOTH a LEAD and a RESIDENT preference set, recipientType is a lens on the person and not a partition of them, so a one-sided check is an incomplete check: read both sides for anyone who exists on both and fail closed on the union. ⚠️ Cache it, never call it per lead: the consent pick list is the tightest hourly bucket on the whole key (60/hour, 10/minute) and one read per lead exhausts the hour on the first sixty. One read a day is generous. Parse defensively too, the rows aren't uniformly shaped (phone and postal_mail can come back with no consentType key at all). Reading a preference is not recording one, writing consent back would be a write and stays barred by rule 2.updateLeads), so Liberty sees exactly that Foothold reached out and what we said. Nothing happens with a contact that the PM can't see. The only exception is bulk marketing (drips/broadcasts), which don't log per-contact. Deferred while rule 2 holds: updateLeads is a write, so on a live production property this logging is deferred, not active. Touches log to the local outbox and stay there, and the relay replays them into Entrata once writes are signed off for that property. The obligation to log is unchanged, only the destination is, and the local record has to be complete enough to replay. Until then "the PM sees everything" is on hold, not waived, so anything Liberty genuinely needs in the moment goes to them by email.getCalendarAvailability does return real, maintained configuration: 30-minute appointments, a hard 120-minute minimum lead time on both tour types, agent-guided Mon–Fri 08:00–16:00 MST, self-guided all 7 days 06:00–18:00 MST, one at a time, with a 7-day maximum query window. So the agent offers windows out of that config and hands the confirmation to a human. ⚠️ An open window is not proof of an open calendar, a tour booked in an agent's head never reaches Entrata, so the agent never asserts a slot is free and double-booking prevention stays ours. ⚠️ Tour hours (08:00–16:00) and the property's documented office hours (M–F 9:00–5:00) disagree by an hour, read both and derive neither. Self-service tour scheduling (Calendly-style, drive-time buffers on either side, the agent nudging leads toward adjacent slots so an agent's day routes efficiently) is Brent's later exploration, explicitly not v1 and not on the critical path.MakeReady was one day before AvailableOn on both available units. Two samples, so it settles nothing either, which is the point. Read the ready date from Entrata where it exists, treat any turn length as a configurable placeholder until Liberty confirms one in writing, and don't put a number in front of a partner before then. Fair housing: yes, this is fine. Move-in timing isn't a protected class, it's a neutral vacancy-minimizing rule. Keep it a written policy, screen everyone by the same criteria first and apply the timing rule among the qualified, and stay open to a reasonable accommodation (a family or disabled applicant who needs a few extra days). Just don't set the window so tight it predictably excludes families/disabled, that's the only disparate-impact risk.- Matched Insiders get the 48-hour early window, texted first, ordered by stated timing closest to the date, waitlist join date as tiebreak.
- Broader waitlist when the early window closes.
- Public listing (Entrata ILS syndication fires).
Priority attaches at application, not interest. The profile's timing is only a soft signal for who to text first; the move-in date that counts, and qualification, come from a completed application. The written allocation rule: among qualified applicants, the completed application that can move in closest to the available date wins. Neutral, mechanical, identical for everyone.
3. Who owns what
| Channel | Owns | Hard line |
|---|---|---|
| Ownership Foothold AI agent | Sales + acquisition + brand. First-touch, qualifying, booking, the listing scorecard, the owner relationship, recognition, and catching escalations (then handing them to Liberty, who owns resolution + SLA) | No rent/lease admin, no operational or pricing promises. Service tickets: today, and permanently at Owyhee Park, the agent points the resident at Entrata's Resident Portal and does not take the request. Target state on NPI-owned properties once live: the agent files the work order itself, after verifying the resident (section 5). Two hard gates first, sendWorkOrders and the rule 2 lift. |
| PM operations Liberty, in Entrata | Operations + voice + listings. Tours, leasing, move-in, maintenance, rent, lease, renewals, all service. Owns all voice/phone (sales calls forward here too) and maintains the listings. | Never leaves Entrata |
4. Recognition touch map (proposed)
My suggestion, building on your leanings: mail for the meaningful and celebratory (and anything with a gift); text for the light, timely, relational. A handwritten card by mail is rarer now, so it lands harder. All from ownership, signed Foothold. (Researching the best card+gift-card API provider now.)
| Moment | Channel | What + tone |
|---|---|---|
| Move-in (welcome packet) | Mail + text | Welcome card + $25 gift card (local). First impression. Once, at move-in. |
| Resident birthday | Mail + text | Handwritten card + $25 gift card (Amazon or local). 1-2/yr (per adult on the lease). Data status 2026-08-05: viable, not solved. Date of birth comes only from getLeads, it's captured at application and never propagates to the lease or resident record, and measured coverage is 57 of 88 current residents (65%). The gap splits two ways: 18 current residents never appear in getLeads at all (no window recovers them) and 13 appear with the field empty. So the Welcome Profile is a REQUIRED component covering the other third, not an optional fallback. Store month and day only, never the year (rule 12). |
| Before renewal (every unit) | Mail + text | Thank-you card + $25 gift card, pet-themed (Chewy) if they have a pet, generic if not. Goes to everyone, not just pet households. Lands ~90 days before renewal, ahead of the ~60-day renewal offer, gift-then-offer reads genuine; offer-then-gift reads like a bribe. The pet half is no longer waiting on data: getLeases carries 34 pet records across 30 of the 52 leases with the pet's name plus breed, color, gender, age, weight and move-in date, joined to the resident on customerId, the same key that joins leads to leases. Capture the whole record, not just the name, breed and age are what make the copy specific. 🚫 isAssistanceAnimal is a HARD fair-housing exclusion, not a matter of tact: assistance and service animals are not pets, they come out of the pet gift and out of every pet-themed message, and a missing or unparseable flag excludes the record. |
| Tenure milestone (1 / 3 / 5 yr) | Card + the experience gift per the tenure ladder. The big ones. | |
| New baby | Card (+ optional meal box). Celebratory, never a gift card. | |
| Engagement / marriage | Text | Light congrats, no gift. Timely beats formal here. |
| Death / hardship | Handwritten sympathy card, no gift card (it'd cheapen it). Sincerity only. | |
| Property updates & changes | Text / email | Proactive heads-up on anything happening (paving next week, new package room, landscaping refresh). A small thing that makes residents feel like they matter and the place is theirs. Via GHL broadcast from ownership. |
What it needs, all readable today with no new permission:
maintenanceProblem, maintenanceLocation and maintenanceDescription off getWorkOrders. Four mandatory filters, all decided elsewhere and inherited here: (1) skip maintenanceRequestFrom: "Entrata PaaS", a system-generated make-ready must never fire a resident message; (2) collapse parent/child on parentMaintenanceRequestId so one turn sends one message, not several; (3) clear the getMarketingPreferences consent gate on both the LEAD and the RESIDENT lens, and a missing preference means don't send; (4) triage on maintenanceProblem and maintenanceLocation, never maintenancePriority (780 of 785 tickets are Medium).
⚠️ A new risk comes with it, and it gets a written rule: the message quotes the resident's own issue back to them, so a wrong or stale detail is worse than a generic message. "Did your back door get fixed?" lands well when it's right and badly when it isn't, and the pick-list values are terse and don't always render into natural language ("Make Ready" is the obvious one, and it's exactly the system-generated case filter 1 already excludes). The rule: the AI renders from the actual field values and never invents detail. If problem and location won't form a natural, confident sentence, fall back to a generic check-in or don't send. Specificity is the point, but a confident wrong guess costs more than it earns. Constitution rule 8 (fair housing) applies, as it does to any AI-generated resident-facing message.
📌 The touch can't be logged into Entrata, and the reason is the RESIDENT record specifically.
sendLeaseActivities, the only method in the 128 that appends an activity to a resident / lease record, is not on the key. So it logs to Foothold's own store. ⚠️ This strengthens the case for the sendLeaseActivities ask: a resident-level service touch is exactly what it would carry. ⚠️ CORRECTION 2026-08-10: this passage used to open with "there is no lead-event write method anywhere in the 128-method spec." That was wrong and it is withdrawn. updateLeads r2 and sendLeads r1 both carry an events array (typeId, date, type, free-text comments) and both are on the key. The decision and the destination are unaffected, because this message goes to a resident, not a lead, and the lease-level half of the reasoning stands on its own. Only the stated rationale was partly wrong. 🚫 And nothing about it loosens anything: appending a lead event is a WRITE, rule 2 governs it completely under the same three conditions, and no write is authorised by a correction about what the API can do. 🚫 Scope: NPI-owned properties once Foothold is live on them. NOT Owyhee Park, which is Liberty's building with Liberty's residents. Everything measured so far was measured at Owyhee, and reading their tickets does not licence messaging their residents.
Still open, deliberately: the completion trigger itself (poll
getWorkOrders versus the workorder.status.update webhook, and which maintenanceStatus values count as complete enough to ask), the timing after completion, and 🆕 whether this message and the review ask in section 6 are one touch or two, which nothing has addressed anywhere. Flagged, not decided.sendLeaseActivities is the only method in all 128 that appends an activity to a record, it is a resident/lease-level write, and it would put these touches in Liberty's system instead of their inbox. It is not on the key, so it takes a new ask, and that ask goes out in the same email as the sendWorkOrders ask: that one is the larger and more consequential write grant, so bundling the low-blast-radius activity note into the same conversation is one round trip instead of two. Frame it to Liberty as what it is for them, less mail, not more. ⚠️ The grant is not the authorization. It is a write, so rule 2 still governs it: the per-property lift plus Brent's written sign-off naming the method, and at Owyhee Park it stays unused even if granted. Interim answer, no permission needed, and permanent at Owyhee: log the touch in Foothold's own store and close Liberty's visibility gap deliberately with a scheduled digest to the property inbox or a read-only Foothold view.postal_mail for the card, sms for the text, they're distinct channels in Entrata's consent record and an opt-out on one doesn't imply the other. Each one gets a follow-up text the night the gift card lands, "just want to make sure you got your package", which confirms receipt and opens the review-ask door (section 6). The other touches carry no gift card (sympathy = card; marriage / property updates = text). Tenure-milestone experience gifts + new-baby boxes are a later add.5. If a resident brings ownership a problem
Liberty owns maintenance, SLA, and resolution, that's what they're paid for, and we don't second-guess it ticket by ticket. But a resident who texts the ownership number with a problem can't be left hanging. Updated 2026-08-05: the intake half of this changes on NPI-owned properties once they're live, see the decision at the bottom of this section. Liberty still owns the work.
- Acknowledge, instantly: "Got your message. This is our property manager Liberty's responsibility and they're great at taking care of you. We've passed it to them and they'll be in touch shortly. – Foothold"
- Hand it to Liberty by email, and let them run it. Answered 2026-08-03 by Alex Costa: a resident or prospect who wants a person goes to Liberty's direct leasing / manager team by email, and
adrienne@libertyassetgroup.comis the right address today. They run Google and Breakroom chats internally but prefer direct email, so build the notification leg as email and don't invent a chat integration. ⚠️ The assistant-manager / leasing team is being restructured and more addresses are coming, so the recipient is per-property config, never a constant in code. Store it with the rest of the per-property config, expect it to become a list per property, and re-verify it when a property is added or a reorg lands. No nightly SLA-policing, that's their job, not ours. ⚠️ Qualified 2026-08-10, not withdrawn: Brent's decision to build an aggregate responsiveness KPI (step 3) doesn't cross this line, because measuring the aggregate is not policing. Alerting on, or chasing, an individual ticket still is. Email is the path today, and at Owyhee Park it is the path permanently:sendWorkOrdershas never been granted (it was still withheld on 2026-08-03 when Liberty put the maintenance reads on the key), and it's a write under rule 2 either way. 🔄 Changed 2026-08-05: it is now a live ask, for NPI-owned properties only, and turning that leg on needs both a Liberty grant and the rule 2 lift for that property. The work-order intent queues in the outbox meanwhile. - Watch the scoreboard, not the plays. We don't monitor individual tickets. If Liberty slips, it shows up in the aggregate, the resident-rating trend, review velocity, and renewals on the scorecard. That's the owner's altitude. ✅ AFFIRMED by Brent 2026-08-10. He chose aggregate over per-ticket policing, so this line stands exactly as written, and it's now a decision he has actually made rather than an unattributed design-intent line. (It's still design intent and not a Constitution rule, so whether to promote it is a separate open question.) The aggregate has a real source now:
getWorkOrdersreads production tickets (status, priority, problem, location,completedOn, scheduled dates, assigned employee), so responsiveness is measurable read-only without touching a single ticket. Two cautions before anything counts or messages off it: filter onmaintenanceRequestFrom, records markedEntrata PaaSare system-generated (make-readies among them) and must never fire a resident-facing touch, and collapse parent/child onparentMaintenanceRequestIdbefore counting, a child record is not an independent ticket.
⚠️ Dual-purpose is a build constraint, not colour. Good numbers become marketing proof for the Foothold thesis; bad numbers become an accountability metric in the Liberty relationship. Both uses demand the same thing: one definition, written down once, computed the same way every time, and never cherry-picked by window. A number used in both directions can't be redefined when it's inconvenient. Write the definition before the first chart.
How it computes, and it needs no new permission and no ask to Liberty:
getWorkOrders carries completedOn (observed in production 2026-08-05) and createdOn (in the vendor spec, not yet observed), plus createdOnFromDate / createdOnToDate / completedOnFromDate / completedOnToDate request filters. Read-only, no rule 2 exposure.
Build cautions, because a naive computation would be wrong: skip
maintenanceRequestFrom: "Entrata PaaS" (7 of 785, turns not resident issues); collapse parent/child on parentMaintenanceRequestId (312 of 785 are children) or one turn counts several times; don't segment on maintenancePriority (780 of 785 are Medium, no signal), use problem and location; ⚠️ createdOn is spec, not observed, so verify it comes back populated before building on it, a single read-only call settles it and if it's empty the metric needs a different clock and the design changes; and consider reporting in-hours versus out-of-hours separately, since office hours are M-F 9:00 to 5:00 with no weekend coverage, so roughly 76% of the week has no staff and a raw aggregate hides that.
Left open on purpose: the target or threshold isn't set. ⚠️ The 24hr / 4hr number on the scorecard is a FIRST CONTACT target, parked at Phase 2 pending Liberty's commitment. It is not a resolution target. And whether this metric joins the six hero KPIs or stays a feeder line is undecided.
sendWorkOrders is NOT on the key and is a new ask to Liberty that has never been made (the maintenance group landed 2026-08-03 with two reads and neither write), and (b) rule 2 must be lifted for that property, meaning NPI-owned, live, and signed off in writing.
⚠️ VERIFY THE RESIDENT BEFORE FILING. An unverified ticket sends a real technician to a real unit. Best identifiers, in order: phone on file is the strongest and cheapest (
getLeases customer phone, getMitsLeases Phone, and an inbound text or call from a matching number is a strong match with zero friction); unit number plus one more factor when the number is unrecognised; and birthDate is a weak primary that must NEVER be the only gate, because coverage is 65%, so a third of residents could not pass it at all. Fail closed: no match means hand off to a human, never file the ticket anyway.
🚫 Until both gates clear, and permanently at Owyhee Park: point residents at Entrata's Resident Portal and do not take the request. That is evidence, not tidiness. Of Owyhee's 785 work orders, 390 (50%) already originate in the Resident Portal, 388 are staff-entered and 7 are system make-readies, and all 71 work-order locations are resident-portal-enabled. Residents have a working intake path that lands directly in the system Liberty's techs work from. Taking a request we cannot file means it sits in a queue while the resident believes it was filed.
⏰ The after-hours problem does not go away when the agent can file. A ticket filed at 11pm Friday still waits for Monday unless someone is on call, against office hours of M-F 9:00 to 5:00 with no weekend coverage. Genuine emergencies get the phone path, never a chat handoff and never an email, before and after the rule lifts.
Two build facts for whoever specs the maintenance engines: priority is effectively unused, 780 of 785 tickets are
Medium (3 Very High, 1 High, 1 Very Low), so triage on maintenanceProblem and maintenanceLocation, not maintenancePriority; and 312 of 785 are child tickets carrying parentMaintenanceRequestId, so collapse parent/child before counting or sending or one turn generates several resident touches.6. Social proof engine (gathering reviews + testimonials)
Reviews are a conversion multiplier on both ends: they lift ILS rank (a listing with ≥1 review gets up to 50% more leads; renters filter on 4.5★) AND they lift the site funnel (land → pick a unit → apply / join the waitlist). So gathering them runs like a machine, timed to the moments residents are happiest.
| Trigger (emotional high) | Why | Ask |
|---|---|---|
| ~2 weeks post-move-in | Settled in, welcome packet landed, strong first impression. (Not day 1, they haven't experienced us yet.) | Auto-text after the welcome packet |
| After a recognition touch | Surprised + delighted by the card / gift, but keep it light. | A soft "just want to make sure you got your package" that opens the door, not a hard ask |
| Lease anniversary / renewal | Committed and loyal, they re-signed. | Auto-text at renewal |
7. Edge cases
Green = locked. Amber = decided, pending an Entrata/API confirmation (research in flight). A Write deferred tag means the decision itself holds but its Entrata write leg is blocked by Constitution rule 2 (see the banner up top), so it queues to the outbox and replays after per-property write sign-off.
| Scenario | Handling | Status |
|---|---|---|
| Resident texts ownership # for a ticket | Today, and permanently at Owyhee Park: redirect, don't take the request. Point them at Entrata's Resident Portal, gently: "service requests go through the resident portal so the techs see them straight away, here's the link." That path already carries 50% of Owyhee's 785 work orders and lands in the system Liberty works from. The number's more visible, so this'll happen, it's fine. Interim: the redirect text still sends, the Entrata log queues in the outbox and anything Liberty needs to act on goes to them by email. 🔄 Target state on NPI-owned properties once live (decided 2026-08-05): the agent verifies the resident and files the ticket itself. Gated on sendWorkOrders (never asked) and the rule 2 lift. Verification order: phone on file, then unit plus one more factor; DOB is never the only gate (65% coverage); fail closed to a human. | Locked Write deferred |
| Guest plays mom & dad | Both read the same Entrata record; agent reads LAG's latest activity before replying and makes no ops/pricing promises; ownership routes back, never overrules. | Locked |
| Any forwarded phone call | ~15 min later the agent texts to confirm they connected + ask for feedback. No need to detect missed-vs-answered. | Locked |
| Emergency by text to ownership # | The live path is phone + email, and it isn't temporary. An emergency alerts LAG by phone and by email to the leasing / manager address (adrienne@libertyassetgroup.com today, per-property config), and the work-order intent queues in the outbox. The priority vocabulary is real and readable: getWorkOrderPickLists is verified live and returns Priorities, StatusTypes, Categories, Problems, Locations and 12 named Liberty employees, property-scoped, so each property needs its own read. ⚠️ At 1,000/day it's the tightest daily bucket on the key, so cache it, one read per property per day, never one per ticket. Filing the work order stays design-only: sendWorkOrders is not on the key at all and is a write under rule 2, so it needs a Liberty grant and the rule 2 lift for that property, and an unverified work order sends a real tech to a real unit. 🔄 Decided 2026-08-05: it is now first in line, as a live ask for NPI-owned properties. ⏰ None of that fixes the after-hours problem, and the emergency answer doesn't change either way: a ticket filed at 11pm Friday still waits for Monday unless someone is on call (office hours M-F 9:00 to 5:00, no weekend coverage), so a genuine emergency gets the phone path, never a chat handoff and never an email, before and after the rule lifts. | Locked Write deferred |
| Agent down / API write fails | Backup email notifies the Liberty PM with the lead + message context, nothing lost while it's down. Under rule 2 this isn't the fallback, it's the primary path for anything Liberty has to act on, since no write reaches Entrata today. Build it first, not last. | Locked |
| Handoff point | Ownership owns through tour completed or application submitted; LAG owns everything after. Plus the one post-tour feedback text. | Locked |
| Tour confirmation + no-show | Agent owns the gap between booked and showed: a confirm text the day before or morning of ("reply to confirm"). If unconfirmed by a couple hours out, one nudge, then the agent notes it "unconfirmed" on the Entrata guest card and LAG decides whether to make the trip. No-show → agent re-engages next day ("want to grab another time?"). Remember the tour was booked by a human, Liberty's agents schedule around their own drive time, so "booked" means Liberty's confirmation, not a slot the agent claimed. Rule 2: the note queues in the outbox, so until writes are signed off the unconfirmed flag reaches LAG by email instead. They still get the call in time to skip the trip. | Locked Write deferred |
| Agent out of its depth mid-conversation | The agent never busks. It tells the guest "let me get a person to follow up on that," emails Liberty's direct leasing / manager team (adrienne@libertyassetgroup.com today, per-property config, they're restructuring), logs an urgent note on the Entrata guest card, and Liberty takes the conversation over from their channel. Escalation human = LAG, not Brent. Rule 2: the urgent note queues in the outbox, so the live hand-off runs entirely on email until writes are signed off. An escalation can't sit in a queue waiting for a permission. Knowing the address still doesn't tell us who reads it at 10 PM on a Friday, the after-hours fork is open. | Locked Write deferred |
| The application itself | Confirmed: it's Entrata's ProspectPortal, live + self-service, and the agent never takes an application itself, it hands out Liberty's hosted URL per property ([property].prospectportal.com/.../application_authentication/), zero friction, apply anytime. ⚠️ The per-property apply link is the one item still open with Liberty (asked 2026-08-03, unanswered): whether every property has one. Don't chase it with a second email. Abandoned-app follow-up: poll getLeads for an in-progress status gone stale, and take the status IDs from getLeadPickLists (62 LeadStatuses, pin them) rather than submitting a test application, which would put a fake applicant in front of a real leasing agent. | Locked Apply link open |
| Which number where | Ownership # on website + marketing. On service surfaces (lease, packet, portal, service-call card), LAG # is bold/front-and-center, with a small footnote: "Feedback for ownership? [Foothold #]." | Locked |
| Ownership # gets service tickets / serves residents | Yes by design, it's the visible, relational number (birthday texts, life events, "got your card?"). Service tickets that land there get auto-saved + redirected to the Resident Portal, which is the right answer today and permanently at Owyhee. On NPI-owned properties, once live and once both gates clear, the redirect becomes a filing: verify the resident, then create the ticket (decided 2026-08-05). Foothold stays the forward-facing brand keeping the PM honest. | Locked |
| Do scorecard + gifts need PM tasks in Entrata? | No tasks, but yes visibility. Gifts auto-send (Handwrytten / Tremendous) and the agent logs a note to the Entrata thread ("mailed birthday card + $25 gift card"), so the PM sees it, no action needed. Scorecard/metrics = a weekly email (or ops-site login), not in Entrata. Actual service tickets/emergencies on the ownership channel get written as work orders LAG acts on. Both Entrata legs (the gift note and the work order) are blocked by rule 2 and queue to the outbox. The gifts still auto-send, and the weekly email is unaffected since it never touched Entrata. ⚠️ The gift-note leg carries a second block, and the ask against it is now moving: sendLeaseActivities is the only method that could append that note, it's not on the key, and Brent put it on the near-term ask list on 2026-08-05, reversing his own deferral from earlier the same day. It rides in the same email as the sendWorkOrders ask. ⚠️ A grant would clear the permission block only, rule 2 still gates the call per property in writing, and at Owyhee it stays unused either way. So the interim visibility path (a digest to the property inbox, or a read-only Foothold view) is what actually closes this in the near term, not a permission. | Locked Write deferred |
8. Context & data freshness (the EliseAI lesson)
The fix is architectural, not just a better prompt. Foothold gets its own datastore (Supabase / Postgres) the agent reads from, kept fresh from Entrata by a background sync. Freshness is tiered, because nightly is fine for amenities but fatal for availability:
| Data | Freshness | How |
|---|---|---|
| Availability + pricing | Near-real-time | Background poll every few minutes into Supabase, plus a live re-check of the specific unit right before the agent quotes it or sends the apply link. This is the EliseAI-proof. |
| Floor plans, amenities, property facts | Slow (nightly) | Nightly Entrata sync. |
| Lead + conversation state | Real-time | Lives in Supabase / GHL, updated as it happens. |
| Resident facts (lease, pets) | Daily | Daily pull for the recognition engine. Lease facts and named pet records come from getLeases; date of birth comes only from getLeads (65% of current residents, the Welcome Profile covers the rest); household grain and customer IDs come from getMitsLeases. Strip SSN and truncate DOB to month + day at the transport boundary (rule 12). |
| Consent state (per channel) | Daily, cached | getMarketingPreferences read before any outbound touch, LEAD and RESIDENT sides, fail closed on the union. Cache the pick-list vocabulary, it's the tightest hourly bucket on the key (60/hour) and must never be called per lead. |
getUnitsAvailabilityAndPricing is generous at 600/minute while getWorkOrderPickLists is 1,000 a day and getMarketingPreferencePickList is 60 an hour, the two tightest buckets on the key, and getStatus at 6/minute can't even be a heartbeat; (3) Entrata takes weekly maintenance windows (Tuesday late night into Wednesday, plus unscheduled ones), so downtime is a normal operating condition. A cache absorbs all three: the poller keeps Supabase fresh inside the serial gate, the agent reads the cache, the live re-check is one targeted call at the commit moment, and last-good cache is what gets served while Entrata is down (alert only past ~2 hours stale).9. The voice question (answered: forward to LAG)
Researched the real 2026 state of AI voice leasing. Verdict: forward calls to LAG for v1. Don't put AI voice on the front door.
- The voice tech is genuinely good now (sub-second latency, natural turn-taking, real interruption handling). "Robotic and awkward" is a 2023 problem.
- But multifamily's problem was never latency, it's the same stale-availability failure that burned Liberty, and it's the #1 complaint in the category, not a fluke. The AI states wrong data with full confidence, worse than a human who'd say "let me check."
- Renters react badly when they realize it's an undisclosed bot. "I'd rather deal with a person."
- Fair-housing risk is about content, not medium (this is right): same brain + guardrails says the same words typed or spoken, so the substantive FHA risk is identical. The only genuine voice delta is auditability (no transcript by default), which we close by transcribing every call to Entrata. HUD treats AI answers as FHA-subject either way.
updateLeads, same as a chat (a write, so it queues to the outbox like every other note until writes are signed off, which is moot for now since voice is parked for v1). With disclosure up front ("this is Foothold's AI assistant, ask for a person anytime") + one-tap transfer, voice is no riskier than chat. So v1 = forward to LAG is purely a sequencing call: prove the data layer + the agent's guardrails on the easier-to-tune chat surface first, then point the same proven brain at voice. A maturity decision, not a liability one.sendLeads and updateLeads, against Owyhee Park, an occupied building, and we're deliberately not using them. (sendWorkOrders and updateWorkOrders were never granted and were still withheld on 2026-08-03 when the maintenance reads landed, so don't read the group's arrival as the writes being close behind. 🔄 Changed 2026-08-05: sendWorkOrders is now a live ask for NPI-owned properties, and it has never been made. updateWorkOrders is not part of it.) What's actually left is ours: (1) the read-only client, a deny-by-default allowlist at the single function that issues requests, failing safe, plus a property-ID allowlist at the same choke point (the key can see 98 other Liberty buildings), in place before the first live call. ⚠️ Build that allowlist PER-PROPERTY from the first line, per the 2026-08-05 decision at the top of this page: the rule lifts on owned properties, so a named property will one day carry a named set of permitted write methods, and a missing or unrecognised property config still means read-only. Retrofitting a per-property gate onto a global bar is where the accident happens; (2) live-availability reads working against the serial gate and the per-method quotas; (3) the outbox, so deferred writes accumulate in replayable form instead of getting dropped; and (4) Brent's written per-property write sign-off naming the property and the methods, which is the only thing that turns the write legs on, and only on a property NPI owns and Foothold is live on. Having the permission was never the authorization to use it. What is genuinely waiting on Liberty is four things, in order: Aspen and Summerset onto the key (the largest unowned dependency before the 8/31 close, and the gate on the whole write half since Owyhee can never carry it), the per-property application link (asked 8/03, unanswered), sendWorkOrders for owned properties (new 8/05, never asked), and 🔄 sendLeaseActivities (added 8/05 when Brent reversed his own deferral the same day, never asked). The last two go out in one email, not two, since sendWorkOrders is the larger grant and the activity note costs nothing extra to name in the same conversation. ⚠️ Neither grant authorizes a call, rule 2 still needs the per-property lift and Brent's written sign-off, and sendLeaseActivities stays unused at Owyhee even if granted. The honest build status: the design is done and the API is fully mapped, but nothing Entrata-facing is built yet, the service still runs in mock mode by choice. Design before code.