Merged into the PropFlow architecture source of truth (2026-08-19) — that page now carries the distilled state of this investigation (§4.6, "Fair-housing screening architecture") alongside the honesty-layer redesign it pairs with. This page remains the full record. Read it there →

Fair-Housing Screening Architecture

PARKED — ownership moved  Parked by Fede on Aug 19, 2026 ("this needs more thinking, can we park it") and on Aug 20 handed to a different agent/workstream to carry — this page is the handoff brief; the original session no longer drives it. Nothing below is being built until this page gets decided. One safe carve-out shipped independently on Aug 20: the voice callback may read taught policies gated to rows that already passed the fair-housing screen — a filter on existing screening, taking no position on any option below. Companion to the Overnight Quality Campaign report.

What's already done (not parked)

What the full audit found (Aug 19, 30-agent sweep, every claim code-verified)

21 confirmed unscreened paths where AI-written or staff-written text reaches a resident or prospect with no fair-housing check. Full evidence with file/line detail: ~/agents/006/fair-housing-audit-2026-08-19.json. The themes:

ThemeWhat happens todayRisk
Maintenance textsA tech's free-text update is rewritten by AI and texted to the resident — nothing screens ithigh
Follow-up campaignsThe AI-personalized outreach and re-engagement messages (text and email) skip the screen entirelyhigh
Residents are exemptThe one screen we have only runs for prospects; any reply to a known resident bypasses it — and accommodation requests mostly come from residentshigh
Voice reads taught policyPhone-call Clara answers from property knowledge, including anything staff taught before the tripwire existed — never screenedhigh
Old taught policiesEverything taught before Aug 19 is still on file unscreened and feeds every conversationmedium
Tour-reminder insertsOperator-written "arrival instructions" go into reminder texts verbatimmedium
Paired-name parityOne live paired test showed different offers to "Emily" vs "DeShawn" — single observation, needs a proper repeated trial before calling it realinvestigate

One audit phase (the "what did we miss" completeness check) aborted on a deleted worktree and should be re-run before treating the list as exhaustive.

Why this is parked instead of patched

Patching 21 call sites one by one bolts a screen onto every lane forever — every new feature reopens the question. The audit suggests the real design questions are structural, and they overlap with the conversation Fede has started with Gera about where policy lives:

  1. Where does the screen sit? Per-lane (today's pattern) vs. once at the send chokepoint (dispatch() / email senders), where every message passes anyway. One gate, impossible to forget — but it must then know audience, capability, and context for every send.
  2. Where does policy live? Today policy is property-level only (PropertyKnowledge). The Gera conversation raises portfolio-level policy. The vision doc's framing: "acts within your policies — tuned to each property's nuances, executed consistently across the portfolio." A policy hierarchy (portfolio default → property override) would also be the natural home for the next layer:
  3. Where does law live? Fede's point: fair-housing law varies by state (vouchers are protected in Colorado, not everywhere). Today the whole portfolio is Colorado so nothing is wrong — but jurisdiction is not modeled anywhere. Before any out-of-state property, the property (or portfolio) record needs a jurisdiction the screen reads.
  4. Screen the source or the mouth? Old taught policies and voice-rendered knowledge suggest screening what's stored (teach-time, already done by the tripwire) plus what's said (send-time) are different jobs; today we have one of each in one lane apiece.

Options when this gets picked up

Option A — Chokepoint screen (recommended draft): one fair-housing gate at the send chokepoints (SMS dispatch + resident-facing email), audience-aware (prospect AND resident), jurisdiction read from the property record (all CO today). Retire the per-lane gate in the agent loop into it. One-time scan of pre-tripwire taught policies. Parity probe run as a proper repeated trial.

Option B — Patch the high-risk lanes only: add the existing screen to maintenance relay + outreach generators + resident audience; leave templates and voice for later. Fastest, but leaves the structural question open and voice unscreened.

Option C — Fold into the policy-hierarchy design with Gera: decide portfolio/property/jurisdiction policy model first; build the screen once against that model. Slowest to first protection, cleanest end state.

A and C combine naturally: A now for protection, C as the model it plugs into.

Cost note

A chokepoint screen adds one fast model call (~$0.001, ~0.1s) per outbound resident/prospect message, and its fail-closed posture means a screening outage pauses outbound sends. Both were accepted for the staff-answer lane; accepting them portfolio-wide is part of this decision.

PropFlow Docs