[object Object]

← back to Rentv 2026

PR intel: linkedin-enrich prioritizes media/PR contacts (org-id set sort)

f40b0bc9a24b3f074a81db532674eac79a6dd93e · 2026-08-05 14:29:13 -0700 · Steve

The /people API has no organization_type filter, so build the media org-id
set from /organizations and sort media contacts first (LI_MEDIA_ONLY filters
to them). Fixes the first batch spending queries on non-media contacts.

Files touched

Diff

commit f40b0bc9a24b3f074a81db532674eac79a6dd93e
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Aug 5 14:29:13 2026 -0700

    PR intel: linkedin-enrich prioritizes media/PR contacts (org-id set sort)
    
    The /people API has no organization_type filter, so build the media org-id
    set from /organizations and sort media contacts first (LI_MEDIA_ONLY filters
    to them). Fixes the first batch spending queries on non-media contacts.
---
 src/pr/tools/linkedin-enrich.js | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/src/pr/tools/linkedin-enrich.js b/src/pr/tools/linkedin-enrich.js
index 8ad12f13..d6d6c590 100644
--- a/src/pr/tools/linkedin-enrich.js
+++ b/src/pr/tools/linkedin-enrich.js
@@ -44,18 +44,19 @@ async function api(p, opts = {}) {
 
 async function main() {
   if (!search.configured()) { console.error('no search key (BRAVE_SEARCH_API_KEY) in rentv/.env — run: node ~/Projects/secrets-manager/cli.js sync'); process.exit(1); }
-  // no-LinkedIn people; media/PR contacts first (they're the outreach targets)
-  const orgTypes = "trade_publication,association,pr_agency,marketing_agency,public_affairs";
-  let targets = [];
+  // Media/PR contacts are the outreach targets — enrich them first. The /people API
+  // has no organization_type filter, so build the media org-id set and sort by it.
+  const MEDIA_TYPES = ['trade_publication', 'association', 'pr_agency', 'marketing_agency', 'public_affairs'];
+  const mediaIds = new Set();
   try {
-    const media = await api(`/people?linkedin_status=none&organization_type=${encodeURIComponent(orgTypes)}&limit=${MAX}`);
-    targets = media.rows || media.people || [];
-  } catch { /* fall through */ }
-  if (!process.env.LI_MEDIA_ONLY && targets.length < MAX) {
-    const more = await api(`/people?linkedin_status=none&limit=${MAX - targets.length}`);
-    const seen = new Set(targets.map((t) => t.id));
-    for (const p of (more.rows || more.people || [])) if (!seen.has(p.id)) targets.push(p);
-  }
+    const orgs = await api(`/organizations?limit=1000`);
+    for (const o of (orgs.rows || orgs.organizations || [])) if (MEDIA_TYPES.includes(o.organization_type)) mediaIds.add(o.id);
+  } catch { /* best effort */ }
+  const pool = (await api(`/people?linkedin_status=none&limit=${Math.max(MAX * 4, 300)}`));
+  let targets = (pool.rows || pool.people || []);
+  if (process.env.LI_MEDIA_ONLY) targets = targets.filter((p) => mediaIds.has(p.organization_id));
+  // media contacts first, then the rest
+  targets.sort((a, b) => (mediaIds.has(b.organization_id) ? 1 : 0) - (mediaIds.has(a.organization_id) ? 1 : 0));
   console.log(`[linkedin-enrich] backend=${search.configured()} targets=${targets.length} (Brave free tier ≈ $0)`);
   let found = 0, queries = 0, miss = 0;
   for (const p of targets.slice(0, MAX)) {

← 493127a2 chore: session close — search buyer/seller/broker on closing  ·  back to Rentv 2026  ·  Cody-gate: posts public-status now published|live in lockste 1fd2ec07 →