[object Object]

← back to Commercialrealestate

broker snapshot: active-listing recency gate + size-ceiling health verdict (DTD A-with-rider)

77b92999a351a14a1f7d3dab6099440e76cc2512 · 2026-08-19 11:38:38 -0700 · Steve

- curCom query: WHERE l.created_at > now()-interval '120 days' — the commercial `listing`
  table has NO status column (mark-off-market runs on the residential table), so a
  created_at recency window is the correctness gate that stops a future stale row from
  surfacing as an ACTIVE listing on a public broker profile. No-op today (all listings
  <=90d); real fix needs a last_seen column (follow-up).
- post-write: emit snapshot-health PASS/WARN/FAIL (fleet-health vocab) + WARN>30MB /
  FAIL>60MB, since readBrokerSnap loads the whole file into the prod Node heap.
Not run here (parallel session just regenerated the snapshot); nightly regen applies it.
Item 1 (snapContact reads brokerDetail) already shipped by the parallel session (fd9337c).

Files touched

Diff

commit 77b92999a351a14a1f7d3dab6099440e76cc2512
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Aug 19 11:38:38 2026 -0700

    broker snapshot: active-listing recency gate + size-ceiling health verdict (DTD A-with-rider)
    
    - curCom query: WHERE l.created_at > now()-interval '120 days' — the commercial `listing`
      table has NO status column (mark-off-market runs on the residential table), so a
      created_at recency window is the correctness gate that stops a future stale row from
      surfacing as an ACTIVE listing on a public broker profile. No-op today (all listings
      <=90d); real fix needs a last_seen column (follow-up).
    - post-write: emit snapshot-health PASS/WARN/FAIL (fleet-health vocab) + WARN>30MB /
      FAIL>60MB, since readBrokerSnap loads the whole file into the prod Node heap.
    Not run here (parallel session just regenerated the snapshot); nightly regen applies it.
    Item 1 (snapContact reads brokerDetail) already shipped by the parallel session (fd9337c).
---
 scripts/export-brokers-snapshot.js | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/scripts/export-brokers-snapshot.js b/scripts/export-brokers-snapshot.js
index a078069..e017a36 100644
--- a/scripts/export-brokers-snapshot.js
+++ b/scripts/export-brokers-snapshot.js
@@ -40,8 +40,15 @@ async function main() {
   const CAP_B = 100, CAP_BX = 12, CAP_F = 300, CAP_FX = 40;
   const rows = (s) => pool.query(s).then(r => r.rows);
   const [curCom, curCon, closedAll, expiredAll] = await Promise.all([
+    // Correctness gate (DTD 2026-08-19, A-with-rider): the commercial `listing` table has NO
+    // status column, so we can't filter sold/off-market by status. It IS actively refreshed
+    // (nothing older than ~90d today), so a created_at recency window keeps a future stale row
+    // from ever surfacing as an ACTIVE listing on a public broker profile. 120d = headroom over
+    // the current ~90d max; widen only if genuinely-active long-listed deals start dropping off.
+    // (A real fix needs a last_seen column on the commercial sweep — tracked as a follow-up.)
     rows(`SELECT bl.broker_id, l.address, l.city, l.zip, l.type, l.price, l.units, l.cap_rate, l.created_at AS listed_at
-            FROM broker_listing bl JOIN listing l ON l.id=bl.listing_id`),
+            FROM broker_listing bl JOIN listing l ON l.id=bl.listing_id
+           WHERE l.created_at > now() - interval '120 days'`),
     rows(`SELECT bc.broker_id, c.address, c.city, NULL::text zip, 'Condo' type, c.price,
                  NULL::int units, NULL::numeric cap_rate, NULL::timestamptz listed_at
             FROM broker_condo bc JOIN condo c ON c.id=bc.condo_id`),
@@ -91,7 +98,16 @@ async function main() {
     source: 'snapshot', exported_at: new Date().toISOString() };
   const dest = path.join(__dirname, '..', 'data', 'brokers-snapshot.json');
   fs.writeFileSync(dest, JSON.stringify(out));
-  console.log(`✔ wrote ${dest} — ${brokers.length} brokers (${(fs.statSync(dest).size/1e6).toFixed(1)}MB)`);
+  const mb = fs.statSync(dest).size / 1e6;
+  console.log(`✔ wrote ${dest} — ${brokers.length} brokers (${mb.toFixed(1)}MB)`);
+  // Size-ceiling guard (DTD 2026-08-19, A-with-rider item 4): readBrokerSnap() loads this ENTIRE file
+  // into the prod Node heap, so runaway growth (more brokers × per-broker books) degrades every CRCP
+  // endpoint. Emit a PASS/WARN/FAIL verdict (fleet-health vocabulary): WARN past 30MB, FAIL past 60MB.
+  // The forward fix past the ceiling is to slice brokerDetail into a lazy-loaded sidecar, not the
+  // always-loaded snapshot.
+  const verdict = mb > 60 ? 'FAIL' : mb > 30 ? 'WARN' : 'PASS';
+  if (verdict !== 'PASS') console.warn(`⚠️  ${verdict}: broker snapshot is ${mb.toFixed(1)}MB (>${mb > 60 ? 60 : 30}MB) — it loads into the prod Node heap; move brokerDetail to a lazy sidecar before it grows further.`);
+  console.log(`snapshot-health: ${verdict} size=${mb.toFixed(1)}MB brokers=${brokers.length}`);
   await pool.end();
 }
 if (require.main === module) main().catch(e => { console.error(e); process.exit(1); });

← 86a32ab Add SFV single-family pool-homes viewer (new crcp landing)  ·  back to Commercialrealestate  ·  CRCP: infinite scroll across all grid pages (replace hard ro 38e4820 →