← back to Rentv 2026
fix(deals): drop an implausibly small SF (<100 sf/unit) next to a unit count — a body-leaked per-unit avg/amenity size, not the asset total ('406 units · 669 SF' → '406 units')
72561ee456f887e8b7c42d1ae1c7112b76641758 · 2026-08-06 07:58:56 -0700 · Steve
Files touched
M scripts/lib/deal-parse.mjsM test/deals/parse.test.mjs
Diff
commit 72561ee456f887e8b7c42d1ae1c7112b76641758
Author: Steve <steve@designerwallcoverings.com>
Date: Thu Aug 6 07:58:56 2026 -0700
fix(deals): drop an implausibly small SF (<100 sf/unit) next to a unit count — a body-leaked per-unit avg/amenity size, not the asset total ('406 units · 669 SF' → '406 units')
---
scripts/lib/deal-parse.mjs | 12 ++++++++----
test/deals/parse.test.mjs | 10 ++++++++++
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/scripts/lib/deal-parse.mjs b/scripts/lib/deal-parse.mjs
index add84472..a4e8e952 100644
--- a/scripts/lib/deal-parse.mjs
+++ b/scripts/lib/deal-parse.mjs
@@ -71,14 +71,18 @@ export function parseSize(text) {
mK && { idx: mK.index, val: Math.round(parseFloat(mK[1].replace(/,/g, '')) * 1e3) },
mPl && { idx: mPl.index, val: +mPl[1].replace(/,/g, '') },
].filter(Boolean).sort((a, b) => a.idx - b.idx);
- const sqft = cands.length ? cands[0].val : null;
+ let sqft = cands.length ? cands[0].val : null;
+ const unitsNum = units ? +units[1].replace(/,/g, '') : null;
+ // Plausibility guard: a multifamily asset is measured in UNITS, not SF, so a small "N sf" next to a
+ // unit count is a body leak — a per-unit average or an amenity/clubhouse size, NOT the total. No
+ // residential building runs under ~100 sf/unit (micro-units start ~250), and real data shows a clean
+ // gap (leaks < 11 sf/unit, legit > 790), so this drops "406 units · 669 SF" → "406 units" safely.
+ if (unitsNum && sqft && sqft < unitsNum * 100) sqft = null;
const parts = [];
if (units) parts.push(`${units[1]} units`);
if (sqft) parts.push(`${sqft.toLocaleString()} SF`);
if (acres) parts.push(`${acres[1]} acres`);
- return { size_label: parts.join(' · ') || null,
- units: units ? +units[1].replace(/,/g, '') : null,
- sqft };
+ return { size_label: parts.join(' · ') || null, units: unitsNum, sqft };
}
export function parseAddress(body) {
diff --git a/test/deals/parse.test.mjs b/test/deals/parse.test.mjs
index 7887b569..0410f722 100644
--- a/test/deals/parse.test.mjs
+++ b/test/deals/parse.test.mjs
@@ -99,6 +99,16 @@ test('parseSize: magnitude-aware (k = thousand, msf = million) and title-first-w
assert.equal(parseSize('104k sf Office Sells. Property is adjacent to 2.5 msf distribution hub.').sqft, 104000);
assert.equal(parseSize('400k sf campus is part of a 3.2 million square feet master plan').sqft, 400000);
});
+test('parseSize: an implausibly small SF next to a unit count is dropped (multifamily body leak)', () => {
+ // a per-unit average / amenity size leaked from the body → drop it, keep the unit count
+ assert.deepEqual(parseSize('Step Up Acquires 406-Unit Portfolio. Each unit averages 669 sf.'),
+ { size_label: '406 units', units: 406, sqft: null });
+ assert.deepEqual(parseSize('BlackRock Acquires 3,620-Unit Portfolio. A 39,000 sf clubhouse anchors it.'),
+ { size_label: '3,620 units', units: 3620, sqft: null });
+ // a plausible large SF next to units is KEPT (not dropped)
+ assert.deepEqual(parseSize('Meta Housing 300-Unit Community spanning 238,000 sf'),
+ { size_label: '300 units · 238,000 SF', units: 300, sqft: 238000 });
+});
// ── parseOccupancy / parseYearBuilt ───────────────────────────────────────────
test('parseOccupancy + parseYearBuilt', () => {
← fa57d846 auto-save: 2026-08-06T07:49:47 (7 files) — data/deals-regist
·
back to Rentv 2026
·
harden(deals): Cody gate — lower SF/unit plausibility thresh f6e330bb →