Handoff for Fede's session 003 (lay-of-the-land page, local harness, prototypes). Answers bridge question q-home-matching-handoff-2026-10-29. Code citations are origin/main as fetched 2026-10-29; prod reads are propflow-prod.
2026-10-29 · written by Agent Smith from the code, git history and prod reads · nothing here is a new decision
There are three matchers, not one. (1) a building matcher that reads the company's alias store, (2) a home matcher over listing rows whose only "alias" is the public listing's title and description, and (3) the newer ADR-0147 address index, wired into phone maintenance and a few leasing paths but not email filing. The alias store is almost empty in prod, and nothing reads a property's internal description.
The current design page for this exact problem already exists and is newer than most of this: lead-to-home-matching-design-2026-10 (2026-10-28, Fede's Pick A). Read it alongside this map. ADR: 0147 one address index for every channel.
src/lib/data/dynamo/property-aliases.ts. Key PK=ORG#<orgId>, SK=PROPALIAS#<normalized>#<id>, one partition per company (line 1). Record shape and kinds (street, nearby street, legal entity, master tenant, house number, close name) live in src/lib/domain/properties/property-aliases.ts (#13966, #14044).text, normalized, targets[] (property, optionally unit ids), source (e.g. learned, pms, geo, onboarding import), status (active / suggested / retired; confirming a suggestion sets it active, and only active rows match, resolve-by-ref.ts:205-216).recordLearnedPropertyName (property-aliases.ts:58) writes a suggested row with empty targets, called from search_properties on a no-match (agents/clara/lib/agent/tools-leasing.ts:12606) and from the named-home-on-company-line path (tools-leasing.ts:3101). People's names are screened out (learned-property-names.ts, #15411/#15498/#15551).src/app/api/properties/[id]/aliases/route.ts + PropertyAliasesCard.tsx ("Other names" card, #14193/#15497/#15499), and Settings › Onboarding "Also known as" via src/app/api/settings/building-names/route.ts (#16012). Nicknames on Building › Settings › Calls & messages (#18146).scripts/import-property-aliases.ts (onboarding spreadsheet, never overwrites a hand edit, #14667/#15020), scripts/import-property-aliases-pms.ts (legal entities from the owner roster, #15346), scripts/backfill-property-aliases-geo.ts (street names from the building's own address, dry-run by default, #16204/#16264).loadPropertyNames in src/lib/domain/leasing/property-name-search.ts:26 (60s cache) feeding answerPropertyNameSearch (:59), which drops every alias with no in-scope target (:65-67). So a suggested learned row never matches anything. Email: agents/clara/lib/email/match-property.ts:312 and match-property-in-text.ts:32. Matching itself: resolvePropertyByName, src/lib/domain/identity/resolve-by-ref.ts:337.src/lib/domain/leasing/listing-resolution.ts: AliasedRow { aliasText? } (:261), listingCandidates (:502), resolveListingTarget (:525). Tiers: exact unit number → same address → name containment → proper-noun phrase in aliasText. More than one hit means ask, never pick (the Ember Estates comment above :502: three homes share the development name in their listing text, so Clara asks which one).resolveListingTarget returns the intake property unchanged ("WEEK 1 … Fan-out replaces this line", :537-540). The property half is identity today.aliasText is built in orgHomeRows, src/lib/domain/leasing/org-home-booking.ts:156, as public listing title + public listing description. It is not the AppFolio property name and not the property's internal description.src/lib/domain/properties/home-match.ts: the prose layer ("which home is this free text about", Fede 2026-09-23) that finds references in email/SMS/post-call text and hands them to listingCandidates (:307). Not a second matcher by design.homeKey, src/lib/domain/leasing/home-key.ts: address identity ("372 Ember Ln" = "372 Ember Lane"), moved to a neutral module in #20363. sameVisitStreetKey (listing-resolution.ts) is a different key, used only by the tour drive buffer.src/lib/domain/properties/address-index/index.ts, resolveAddress(...): confidence ladder exact / likely / close / guess / off_roster; only exact files a work order unconfirmed (#21201, #21406, #21418).src/lib/domain/maintenance/spoken-home-resolver.ts, src/lib/domain/leasing/tour/block-home.ts, src/lib/domain/portfolio/context/mint.ts, src/lib/integrations/voice/postcall-prospect-capture.ts. Not the email filer (match-property.ts).western-slope-front-door; Situs's 720 line → situs-front-door, both scattered_site) resolves to an anchor property marked as a company-line umbrella (isCompanyLineUmbrella, #11801; stamping script scripts/stamp-company-line-umbrella.ts). Line → property map: config/phone-registry.json.namedHomeOnUmbrellaLine (tools-leasing.ts:3033) and pickOrgHome / resolveOrgHomeForLine (org-home-booking.ts:281, :499) pick the home across the company, fenced to the line's coverage (fenceOrgHomesToLineCoverage, :413).aliasText source): the listings-sync program in config/automations.toml, Vercel cron /api/cron/listings-sync, every 15 min, scraping the public AppFolio listings page.origin/main for .description / internalNotes reads in the leasing domain, the email matchers, the tools dir and the Clara agent dir found no matcher reading it (control: the same grep finds aliasText in listing-resolution.ts). An alias note written there is invisible to every matcher.| Channel | Building step | Home step | Notes |
|---|---|---|---|
| Voice (leasing) | Dialled line → property at call start (phone-registry.json). search_properties is NOT bound to the voice agent (src/lib/tools/leasing.ts:1252-1257, agents: []; note in leasing.config.json:2). On an umbrella line the home is picked by resolveOrgHomeForLine (tools-leasing.ts:8214) and mapped to the child building by resolveCompanyLineHome (front-door-unit-home.ts:233). | schedule_tour (handleScheduleTourImpl, :7788) → resolveListingTarget (:8434) with listingCandidates for the "which one?" list (:8448). Umbrella line: pickOrgHome. | A home the caller names wins on a many-homes line (#17157, #17727). Post-call guest card uses resolveAddress (postcall-prospect-capture.ts). |
| Voice (maintenance) | Dialled line. | spoken-home-resolver.ts → ADR-0147 resolveAddress. | Emergencies never wait on a match. |
| Text | Dialled number → property, then resolvePropertyContext (tools-leasing.ts:1971) → resolveNamedBuilding (:3067) → searchPropertyByName (alias store). search_properties → handleSearchPropertiesImpl (:12463); a no-match writes a learned suggested name (:12606). | home-match.ts over the message, then listingCandidates. | Company-line texts on the address index since #21406. |
| Email / guest card (ILS lead) | match-property.ts → matchPropertyByNamedHome (:308) → resolvePropertyByName(…, { strict: true }) (:274) with the alias store; find-property-in-text.ts:88 scans prose. | home-match.ts → listingCandidates. | Order: recipient address (match-property.ts:155) → named home in body (process-inbound-email.ts:1721; a tie stops routing) → subject-line scorer match-property-by-name.ts:261, which reads no aliases. Guest card: parse-lead-source.ts:657 → apply-parsed-lead-facts.ts:297 → resolveGuestCardHome (guest-card-home.ts:280) → pickOrgHome → resolveListingTarget. Not on the address index. Fede's 10-28 page: 9 of the 10 still-failing known misses are on email filing. #23382 (merged 10-29) ignores a generic tail word in the named building. |
| Staff tools | find-prospect-for-staff.ts:192, handle-forward-to-property-manager.ts:877 → resolvePropertyByName (no aliases passed). | — | Staff-typed address matching #15978. |
Voice tool route: src/app/api/voice/tools/[tool]/route.ts:199 → handleLeasingToolCall (tools-leasing.ts:891). Property names: AppFolio wins (property-directory-refresh.ts:93), refreshed on the 15-min listings tick; company listings live separately in ORG#/LISTING# rows.
[propflow-prod] ORG#org_c42d9150-…/PROPALIAS#* → 2 rows (Western Slope; org id from config/elevenlabs-phone-numbers.json) "2858 C 1/2 Rd" source=learned status=suggested targets=[] seenCount=2 "585 Redcliff Cir" source=learned status=suggested targets=[] seenCount=1 [propflow-prod] ORG#org_a3376147-…/PROPALIAS#* → no row (Situs; org id from situs-front-door's organizationId)
Not checked for this page: which current Western Slope listing rows carry "Ember" in their listing text after the renames. That is the next read for the harness.
resolveListingTarget's property half is identity until fan-out (listing-resolution.ts:537).listingCandidates, and listing text never reaches the building matcher.resolvePropertyByName and the email subject-line scorer use no aliases.search_properties unbound), so on a company line the building comes only from the home match.src/lib/domain/portfolio/scope/index.ts says "NOTHING READS THIS YET"; it is not a property resolver.#13966 alias records · #14044 name kinds · #14661 strict mode · #14667/#15020 spreadsheet loader · #14685 map-lookup streets · #14193/#15497/#15499 names editor · #14676/#15343/#15370/#14677 one matcher for guest card, staff desk, search_properties · #15411/#15498/#15551 learned names · #15461 master tenants · #15346 legal entities · #15978 staff-typed addresses · #16012/#16073 "Also known as" · #16204/#16264 geo streets · #17157/#17727 named home wins on a many-homes line · #18146 nicknames · #18346 no owner-roster prefill · #18495 home by name without a number · #19739 umbrellas out of the availability heartbeat · #20363 homeKey to a neutral module · #21201/#21406/#21418 ADR-0147 address index · #23382 email lead files on the named building. Earlier: #8610, #8621, #9418, #9420, #9554, #11801.