Builder Name Resolution
Four resolvers that turn messy permit and MLS names into one trustworthy builder and community. This is the join key the Market Report depends on. Repo: builder_resolving_cc.
Why we have it
Every source mislabels who built a home, in a different way. A building permit lists five or more companies (contractor, owner, applicant, subs, architect), and the legacy logic just coalesced them, so it routinely tagged an electrician, architect, or lot owner as the builder (about 15,000 mislabeled). An MLS "builder" field is usually the listing brokerage (Coldwell Banker, RE/MAX), so about a third of listings showed a real-estate office as a homebuilder. The MLS community field is free text with mixed casing, county-code suffixes, and phase markers. Until builder is separated from brokerage and names are made canonical, every Hayden-versus-competitor number in the Market Report is wrong. This is the number one blocker.
How it works
flowchart TB
classDef src fill:#e7eef2,stroke:#2e5a6e,color:#1a2530;
classDef proc fill:#f6ecd9,stroke:#b5731f,color:#1a2530;
classDef shared fill:#f6efe0,stroke:#8a6d2f,color:#1a2530,font-weight:600;
classDef store fill:#efe7f2,stroke:#7a5a8e,color:#1a2530;
classDef out fill:#e7f0ea,stroke:#1f7a4d,color:#1a2530;
classDef val fill:#eef5f0,stroke:#1f7a4d,color:#11402a,font-weight:600;
shared["builder_utils.py: shared canonical dictionary
(entity normalize + builder / sub / architect / person classifiers)"]:::shared
subgraph PERMIT["Permit side"]
direction TB
cm["Bronze CM_PERMIT_DATA
(companylinks JSON, 5+ companies per permit)"]:::src
alb["Albany Accela scraper
PDF to licensed contractor (ground truth)"]:::src
t1["Tool 1 . resolve_permit_builders.py
tiered waterfall: master, fuzzy,
weighted role scorer, supplemental, classify
(self-improves the master each run)"]:::proc
plk[("PERMIT_BUILDER_LOOKUP")]:::store
cm --> t1
alb -->|ground-truth override| t1
t1 --> plk
end
subgraph MLS["MLS side"]
direction TB
mls1["Silver MLS . SOURCE_BUILDER"]:::src
mls2["Silver MLS . SUBDIVISION"]:::src
t2["Tool 2 . resolve_mls_builders.py
waterfall + brokerage detection
(brokerage to NULL, flagged)"]:::proc
t3["Tool 3 . resolve_mls_community.py
normalize, match KOVA + competitor communities"]:::proc
mlk[("MLS_BUILDER_LOOKUP")]:::store
clk[("MLS_COMMUNITY_LOOKUP")]:::store
mls1 --> t2 --> mlk
mls2 --> t3 --> clk
end
shared -.imported by.-> t1
shared -.imported by.-> t2
plk -.master grows.-> shared
dbt["dbt: 3 LEFT JOINs back onto Silver
Permits.sql . MLS.sql (Prefect computes, dbt joins)"]:::out
gold["Gold: clean builder + community + geo"]:::out
val["Accurate builder share, price-vs-size competitive map,
and supply. Feeds Power BI, the Market Report,
and the chatbot."]:::val
plk --> dbt
mlk --> dbt
clk --> dbt
dbt --> gold --> val
90.3%permits labeled
(~586K permits, Tool 1)
47 to 96%MLS builder cleaned
(Tool 2; 34% flagged brokerage)
0 to 98.7%MLS communities cleaned
(Tool 3; 17,533 subdivisions)
94%Albany PDF contractor hit-rate
(Tool 4)
What each resolver does
- Tool 1, CM permits. Scores every company on each permit by role, volume, and name analysis, then writes one builder per permit. Confident results are appended back into the master, so the next run resolves them instantly.
- Tool 2, MLS builder. Separates the real builder from the listing brokerage, and flags brokerages instead of mislabeling them.
- Tool 3, MLS community. Normalizes free-text subdivisions to canonical Hayden and competitor community names.
- Tool 4, Albany Accela. Extracts the licensed contractor from permit PDFs as ground truth. Extensible to any Accela city.
- Pattern. Each tool cleans a name in place and writes a small Snowflake lookup that dbt joins back. Standard library only. NULL rather than a guess. Prefect computes (permits daily, MLS and Albany weekly); dbt joins.
How it connects to the rest of the stack
Feeds the Market Report (Power BI and the chatbot) through the three dbt joins. It is the join key for builder market share, the competitive space map, and supply.
Shares its dictionary with Parcela. Parcela vendors the same builder master and name-canonicalizer to flag Hayden-owned and competitor-owned land the same way.
How it can expand
- Add more Accela cities for licensed-contractor ground truth.
- Fold the resolved column into the canonical Builder field and retire the legacy lookups (Phase 2).
- Add periodic human review of the self-improving master's new auto-entries.