[object Object]

← back to Rentv

fix(deals): summarize() collapses whitespace runs — the sentence class absorbed leading spaces so join yielded 'end. Start' (2-3 spaces) on 30% of the LIVE corpus's customer-facing deal-card summaries. \s+→' ' normalizes (also flattens tab/newline from fetched bodies). Updated 2 tests that pinned the artifact + added a source-multispace test. 61/0

ef48e64f364885d20a20baa3e85f5ac1e272eca5 · 2026-08-06 14:23:53 -0700 · Steve

Files touched

Diff

commit ef48e64f364885d20a20baa3e85f5ac1e272eca5
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Aug 6 14:23:53 2026 -0700

    fix(deals): summarize() collapses whitespace runs — the sentence class absorbed leading spaces so join yielded 'end.  Start' (2-3 spaces) on 30% of the LIVE corpus's customer-facing deal-card summaries. \s+→' ' normalizes (also flattens tab/newline from fetched bodies). Updated 2 tests that pinned the artifact + added a source-multispace test. 61/0
---
 scripts/lib/deal-parse.mjs |  7 ++++++-
 test/deals/parse.test.mjs  | 11 +++++++++--
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/scripts/lib/deal-parse.mjs b/scripts/lib/deal-parse.mjs
index 8c693f85..b250f4a7 100644
--- a/scripts/lib/deal-parse.mjs
+++ b/scripts/lib/deal-parse.mjs
@@ -132,5 +132,10 @@ export function summarize(title, body) {
   if (ti >= 0) b = b.slice(ti + title.length);
   b = b.replace(/^\s*\d{1,2}\/\d{1,2}\/\d{2,4}\s*/, '').trim();
   const sentences = b.match(/[^.!?]+[.!?]+/g) || [b];
-  return sentences.slice(0, 2).join(' ').trim().slice(0, 320);
+  // Collapse whitespace runs to a single space: the sentence class [^.!?]+ greedily absorbs the
+  // space(s) AFTER the prior sentence's period, so each captured sentence carries leading whitespace
+  // and join(' ') then yields "end.  Start" (2–3 spaces). 30% of the live corpus's summaries showed
+  // this artifact on the customer-facing deal card. \s+→' ' normalizes it (also flattens stray tabs/
+  // newlines from the fetched body) before the length cap.
+  return sentences.slice(0, 2).join(' ').replace(/\s+/g, ' ').trim().slice(0, 320);
 }
diff --git a/test/deals/parse.test.mjs b/test/deals/parse.test.mjs
index feb8904c..b957f86e 100644
--- a/test/deals/parse.test.mjs
+++ b/test/deals/parse.test.mjs
@@ -156,18 +156,25 @@ test('parseOccupancy + parseYearBuilt', () => {
 test('summarize: strips the leading title echo + a date stamp, keeps 2 sentences', () => {
   assert.equal(
     summarize('ACME Buys Tower', 'ACME Buys Tower 08/05/2026 The asset sold for $50 mil. It spans 200k sf. A third sentence.'),
-    'The asset sold for $50 mil.  It spans 200k sf.',
+    'The asset sold for $50 mil. It spans 200k sf.', // single space — whitespace runs collapsed (was a double-space artifact)
   );
 });
 test('summarize: body without the title echo → first two sentences', () => {
   assert.equal(
     summarize('Unrelated Title', 'First sentence about the deal. Second sentence with detail. Third one ignored.'),
-    'First sentence about the deal.  Second sentence with detail.',
+    'First sentence about the deal. Second sentence with detail.', // single space (collapsed)
   );
 });
 test('summarize: empty body → empty string (never throws)', () => {
   assert.equal(summarize('Any Title', ''), '');
 });
+test('summarize: collapses multi-space / tab / newline runs from the fetched body (30% of live corpus)', () => {
+  // The body itself carries double spaces + a newline (real fetched-article artifact); output must be clean.
+  assert.equal(
+    summarize('X', 'X  A newly built tower traded.  It spans 200k sf.\n\tBroker was CBRE.'),
+    'A newly built tower traded. It spans 200k sf.',
+  );
+});
 test('summarize: single clause with no terminal punctuation is kept whole', () => {
   assert.equal(summarize('T', 'Just one clause with no terminal punctuation'), 'Just one clause with no terminal punctuation');
 });

← 4c3bc491 feat(services): per-firm pitch note rides into the /social l  ·  back to Rentv  ·  auto-data-snapshot: 2026-08-06T14:29:57 (8 data files) — dat 0007cc49 →