[object Object]

← back to Rentv 2026

PR intel: tighten LinkedIn slug guard to require surname (Cody fix)

676a7464c3b978dc6628ef493a6e796a91ac5151 · 2026-08-05 14:49:22 -0700 · Steve

yoloforever cycle 1 / Cody FIX-FIRST: the guard used toks.some() so any name
token (incl. first name) accepted a match — 'Rob Chen' would accept
rob-johnson-cbre. Now require the LAST-NAME token in the slug AND a first-name/
initial signal. Rejects namesakes, keeps real matches. Protects the 6am job.

Files touched

Diff

commit 676a7464c3b978dc6628ef493a6e796a91ac5151
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Aug 5 14:49:22 2026 -0700

    PR intel: tighten LinkedIn slug guard to require surname (Cody fix)
    
    yoloforever cycle 1 / Cody FIX-FIRST: the guard used toks.some() so any name
    token (incl. first name) accepted a match — 'Rob Chen' would accept
    rob-johnson-cbre. Now require the LAST-NAME token in the slug AND a first-name/
    initial signal. Rejects namesakes, keeps real matches. Protects the 6am job.
---
 src/pr/tools/linkedin-enrich.js | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/pr/tools/linkedin-enrich.js b/src/pr/tools/linkedin-enrich.js
index d6d6c590..8dbe50b9 100644
--- a/src/pr/tools/linkedin-enrich.js
+++ b/src/pr/tools/linkedin-enrich.js
@@ -66,12 +66,17 @@ async function main() {
     try {
       const rep = await linkedin.locatePerson({ full_name: p.full_name, organization_name: orgName });
       const hit = (rep.items || [])[0];
-      // Guard against wrong-person matches: the /in/ slug must share a name token with
-      // the person (Brave's top result is often a namesake). Reject obvious mismatches
-      // rather than store a wrong profile.
+      // Guard against wrong-person matches: the /in/ slug must contain the LAST-NAME
+      // token (Cody, cycle 1). First names are far too common — "Rob Chen" must NOT
+      // accept `rob-johnson-cbre`. Requiring the surname is the real namesake filter.
       const slug = ((hit && hit.linkedin_url) || '').match(/\/in\/([^/?#]+)/);
       const toks = String(p.full_name).toLowerCase().split(/\s+/).map((t) => t.replace(/[^a-z]/g, '')).filter((t) => t.length > 2);
-      const slugOk = slug && toks.some((t) => slug[1].toLowerCase().includes(t));
+      const lastTok = toks[toks.length - 1];
+      const slugStr = slug ? slug[1].toLowerCase() : '';
+      // require surname; also require a first-name/initial signal so "smith" ≠ any Smith
+      const firstTok = toks[0];
+      const slugOk = slug && lastTok && slugStr.includes(lastTok)
+        && (!firstTok || firstTok === lastTok || slugStr.includes(firstTok) || slugStr.includes(firstTok[0]));
       if (hit && hit.linkedin_url && slugOk) {
         await api('/people/' + p.id, { method: 'PUT', body: {
           linkedin_url: hit.linkedin_url, linkedin_status: 'found_uncorroborated',

← dbc79b26 RENTV closings+deals editors: drill-down on every datum — ba  ·  back to Rentv 2026  ·  Cody-gate: buyer/seller/broker are now admin-editable (added dfe922fe →