← back to Govarbitrage
agents: drop financial-advisory/wealth firms from CRE finder
2d441932f06e4cb83cb5bc1de3506105fac18593 · 2026-07-27 21:23:40 -0700 · Steve Abrams
The broker/finance verticals overlap, so a Places text search for
'commercial real estate broker' surfaces wealth-management, financial-
advisory and securities firms. Their names carry finance-ambiguous
tokens (investments/advisors/capital markets) that also satisfy the
generic COMMERCIAL_RE keep, so 'Sterling Financial Advisors',
'Vanguard Investment Advisors', 'Edward Jones Investments' etc. were
wrongly kept as CRE brokers (the finance type-gate only catches
Google-tagged finance; many wealth firms come back as establishment/POI).
Add a financial-advisory name gate that runs before the commercial keep:
a wealth/securities/financial firm is dropped UNLESS it carries an
unambiguous real-estate anchor (real estate/realty/CRE/properties/
leasing/net lease/investment sales/commercial) or an allowlisted CRE
brand. 'investment sales' stays a CRE anchor so legit investment-sales
brokers survive. +18 offline regression tests, 131/131, tsc+eslint clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M src/lib/places.test.tsM src/lib/places.ts
Diff
commit 2d441932f06e4cb83cb5bc1de3506105fac18593
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Jul 27 21:23:40 2026 -0700
agents: drop financial-advisory/wealth firms from CRE finder
The broker/finance verticals overlap, so a Places text search for
'commercial real estate broker' surfaces wealth-management, financial-
advisory and securities firms. Their names carry finance-ambiguous
tokens (investments/advisors/capital markets) that also satisfy the
generic COMMERCIAL_RE keep, so 'Sterling Financial Advisors',
'Vanguard Investment Advisors', 'Edward Jones Investments' etc. were
wrongly kept as CRE brokers (the finance type-gate only catches
Google-tagged finance; many wealth firms come back as establishment/POI).
Add a financial-advisory name gate that runs before the commercial keep:
a wealth/securities/financial firm is dropped UNLESS it carries an
unambiguous real-estate anchor (real estate/realty/CRE/properties/
leasing/net lease/investment sales/commercial) or an allowlisted CRE
brand. 'investment sales' stays a CRE anchor so legit investment-sales
brokers survive. +18 offline regression tests, 131/131, tsc+eslint clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
src/lib/places.test.ts | 48 +++++++++++++++++++++++++++++++++++++++
src/lib/places.ts | 61 ++++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 102 insertions(+), 7 deletions(-)
diff --git a/src/lib/places.test.ts b/src/lib/places.test.ts
index abb9f35..b6daebc 100644
--- a/src/lib/places.test.ts
+++ b/src/lib/places.test.ts
@@ -153,6 +153,54 @@ describe("isCommercial — DROP on off-topic Google place types (regardless of n
});
});
+// Regression: the "broker" and "finance" verticals overlap, so a Places text
+// search for "commercial real estate broker" surfaces WEALTH / FINANCIAL-
+// ADVISORY / securities firms. Their names carry finance-ambiguous tokens
+// ("investments", "advisors", "capital markets") that ALSO satisfy the generic
+// COMMERCIAL_RE keep — so before the fix, "Sterling Financial Advisors" and
+// "Vanguard Investment Advisors" were WRONGLY kept as CRE brokers. Now a
+// financial-advisory name with NO real-estate anchor is dropped, while a legit
+// CRE broker (which carries an RE anchor or an allowlisted brand) is preserved.
+describe("isCommercial — DROP on financial-advisory / wealth firms with no RE anchor", () => {
+ it.each([
+ "Morgan Stanley Wealth Investments",
+ "Sterling Financial Advisors",
+ "Vanguard Investment Advisors",
+ "Edward Jones Investments",
+ "Pinnacle Wealth Advisors",
+ "Fidelity Asset Management",
+ "Prudential Insurance Advisors",
+ "Cornerstone Wealth Management",
+ "Cambridge Investment Management",
+ "Heritage Retirement Advisors",
+ ])("drops finance firm %s (no real-estate anchor)", (name) => {
+ expect(isCommercial(place(name))).toBe(false);
+ });
+
+ it.each([
+ // A real-estate anchor rescues a finance-ambiguous name — these are real CRE.
+ "Net Lease Advisors", // "net lease" + "leasing" anchor
+ "Metro CRE Advisors", // "CRE" anchor
+ "Apex Investment Sales", // "investment sales" is the CRE-specific phrase
+ "Harbor Income Properties", // "properties" anchor
+ "Commercial Real Estate Investment Advisors", // "real estate" anchor
+ "Summit Capital Markets", // capital markets alone isn't a finance-drop token
+ ])("keeps CRE broker %s despite a finance-ambiguous word", (name) => {
+ expect(isCommercial(place(name))).toBe(true);
+ });
+
+ it("keeps an allowlisted CRE brand even when the name carries a finance word", () => {
+ // Brand allowlist overrides the financial-advisory drop.
+ expect(isCommercial(place("CBRE Investment Management"))).toBe(true);
+ expect(isCommercial(place("JLL Capital Markets"))).toBe(true);
+ });
+
+ it("still keeps a plainly-commercial broker with no finance word at all", () => {
+ // Guard against the finance gate over-reaching into ordinary CRE names.
+ expect(isCommercial(place("Downtown Commercial Leasing"))).toBe(true);
+ });
+});
+
describe("isCommercial — DROP on residential-flavored place types", () => {
it.each(["apartment_complex", "home_goods_store"])("drops type %s with no commercial name", (type) => {
expect(isCommercial(place("Parkview", [type]))).toBe(false);
diff --git a/src/lib/places.ts b/src/lib/places.ts
index 962f3f6..7c4b9bf 100644
--- a/src/lib/places.ts
+++ b/src/lib/places.ts
@@ -163,11 +163,48 @@ function isOffTopicType(t: string): boolean {
// reason as above). Complements the off-topic blocklist for apartment/home mis-tags.
const RESIDENTIAL_TYPES = new Set(["apartment_complex", "home_goods_store"]);
+// FINANCIAL-ADVISORY / wealth / securities name signals — the "broker" and
+// "finance" verticals overlap, so a Places text search for "commercial real
+// estate broker" reliably surfaces wealth-management, financial-advisory and
+// securities firms. Google's `finance` type-gate only catches the ones Google
+// explicitly tagged finance; many advisory firms come back tagged
+// `establishment`/`point_of_interest` and slip past it. These names carry the
+// finance-ambiguous tokens ("investments", "advisors", "capital markets") that
+// ALSO appear in legit CRE names, so a firm matching this is dropped UNLESS it
+// also carries an unambiguous real-estate anchor (RE_ANCHOR_RE, below).
+// Note: "investment sales" is a CRE-specific phrase and is EXCLUDED here (it's a
+// real-estate anchor, below) — only bare "investment(s)" / "investment advisors"
+// (with no RE anchor) reads as a wealth firm. The negative lookahead on
+// "investment" avoids matching "investment sales".
+const FINANCIAL_ADVISORY_RE =
+ /\b(wealth|financial\s+advisors?|financial\s+planning|financial\s+services|financial\s+group|securities|asset\s+management|wealth\s+management|investment\s+management|investment\s+advisors?|investments?(?!\s+sales)|private\s+equity|hedge\s+fund|insurance|retirement|portfolio\s+management|mutual\s+funds?|stockbrokers?|401k?)\b/i;
+
+// Unambiguous REAL-ESTATE anchor words. Presence of one proves a
+// finance-ambiguous name (e.g. "Investment Sales Advisors") is genuinely a
+// commercial-RE broker and not a wealth firm, so it survives the financial-
+// advisory drop. "real estate" / "realty" / "property/properties" / "leasing"
+// are the reliable RE anchors; "CRE" and "commercial real estate" too.
+const RE_ANCHOR_RE =
+ /\b(real\s+estate|realty|CRE|propert(?:y|ies)|leasing|net\s+lease|tenant\s+rep(?:resentation)?|multifamily|land\s+brokerage|investment\s+sales|commercial)\b/i;
+
function hasCommercialBrand(name: string): boolean {
const n = name.toLowerCase();
return COMMERCIAL_BRANDS.some((b) => n.includes(b));
}
+// True when the name reads as a financial-advisory / wealth firm that lacks a
+// real-estate anchor — i.e. a finance false-positive we must drop even though a
+// bare finance-ambiguous token (investments/advisors/capital markets) would
+// otherwise satisfy COMMERCIAL_RE. An allowlisted CRE brand always overrides
+// (a real brokerage that happens to include "insurance" etc. in its name stays).
+function isFinancialAdvisoryNoRE(name: string): boolean {
+ return (
+ FINANCIAL_ADVISORY_RE.test(name) &&
+ !RE_ANCHOR_RE.test(name) &&
+ !hasCommercialBrand(name)
+ );
+}
+
// --- Commercial-relevance ranking weight ----------------------------------
// Every result in the ranked list has ALREADY passed isCommercial() (precision
// gate), but they're not equally strong CRE-broker matches. A listing that is
@@ -312,12 +349,17 @@ function locationString(city?: string, state?: string, zip?: string): string {
// evidence (a strong name signal or an allowlisted brokerage brand) to keep a
// result, instead of defaulting to keep. Apply order:
// 1. Off-topic Google type (travel/lodging/storage/…) → DROP regardless.
-// 2. Strong commercial name signal OR allowlisted brand → KEEP (wins over
+// 2. Financial-advisory / wealth firm WITHOUT a real-estate anchor → DROP.
+// (Runs before the commercial keep because finance names carry ambiguous
+// "investments"/"advisors"/"capital markets" tokens that would otherwise
+// satisfy COMMERCIAL_RE — e.g. "Sterling Financial Advisors" is a wealth
+// firm, not a CRE broker. An allowlisted CRE brand overrides this.)
+// 3. Strong commercial name signal OR allowlisted brand → KEEP (wins over
// any residential signal, e.g. "Commercial Realty Advisors").
-// 3. Residential / irrelevant name signal → DROP.
-// 4. Residential-flavored place type → DROP.
-// 5. Generic real-estate result with no commercial evidence → DROP.
-// 6. Non-real-estate result with no signal either way → DROP (nothing kept it).
+// 4. Residential / irrelevant name signal → DROP.
+// 5. Residential-flavored place type → DROP.
+// 6. Generic real-estate result with no commercial evidence → DROP.
+// 7. Non-real-estate result with no signal either way → DROP (nothing kept it).
export function isCommercial(p: RawPlace): boolean {
const name = p.displayName?.text ?? "";
const types = [p.primaryType ?? "", ...(p.types ?? [])];
@@ -328,7 +370,12 @@ export function isCommercial(p: RawPlace): boolean {
const hasResidentialType = types.some((t) => RESIDENTIAL_TYPES.has(t.toLowerCase()));
- // 2. Positive commercial evidence wins over everything below.
+ // 2. Financial-advisory / wealth / securities firm with no real-estate anchor →
+ // drop. Guards against the broker↔finance vertical overlap that surfaces
+ // wealth firms on a "commercial real estate broker" text search.
+ if (isFinancialAdvisoryNoRE(name)) return false;
+
+ // 3. Positive commercial evidence wins over everything below.
if (COMMERCIAL_RE.test(name) || hasCommercialBrand(name)) return true;
// 3. Explicit residential / irrelevant name → drop.
@@ -337,7 +384,7 @@ export function isCommercial(p: RawPlace): boolean {
// 4. Residential-flavored place type with no commercial evidence → drop.
if (hasResidentialType) return false;
- // 5 & 6. No commercial evidence at all — whether or not it's a generic
+ // 6 & 7. No commercial evidence at all — whether or not it's a generic
// real_estate_agency, we can't confirm it's commercial, so drop it.
// (Precision > recall: the page promises commercial-only.)
return false;
← c53b1f2 agents: relevance-weighted ranking — surface stronger CRE ma
·
back to Govarbitrage
·
auto-save: 2026-07-27T21:24:43 (1 files) — tsconfig.tsbuildi a2ed0e6 →