[object Object]

← back to Rentv

pr-intelligence: Cody c4 — person.rejected audit logging, company-suffix HARD words, senior-title→leadership dept default; 28 industry associations added (Steve-directed)

aed80d099dc87cef922d9ec326602ac601e9e2a8 · 2026-07-30 20:42:14 -0700 · Steve Abrams

Files touched

Diff

commit aed80d099dc87cef922d9ec326602ac601e9e2a8
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jul 30 20:42:14 2026 -0700

    pr-intelligence: Cody c4 — person.rejected audit logging, company-suffix HARD words, senior-title→leadership dept default; 28 industry associations added (Steve-directed)
---
 src/pr/lib/normalize.js   | 5 +++++
 src/pr/lib/taxonomy.js    | 6 ++++++
 src/pr/services/people.js | 4 ++++
 3 files changed, 15 insertions(+)

diff --git a/src/pr/lib/normalize.js b/src/pr/lib/normalize.js
index a959490c..d3d2051c 100644
--- a/src/pr/lib/normalize.js
+++ b/src/pr/lib/normalize.js
@@ -90,6 +90,11 @@ const HARD_NONNAME_WORDS = new Set([
   'welcome', 'careers', 'privacy', 'policy', 'profile', 'profiles', 'employee',
   'employees', 'portal', 'menu', 'website', 'contact', 'services', 'staff', 'why',
   'how', 'what', 'statement', 'client', 'clients', 'testimonials', 'awards',
+  // Cody c4 sample: company/product strings that passed ("Glen Oaks Escrow",
+  // "Transportation Pollution Liability")
+  'escrow', 'liability', 'pollution', 'transportation', 'insurance', 'financial',
+  'holdings', 'ventures', 'advisors', 'associates', 'investments', 'equity', 'capital',
+  'inc', 'llc', 'llp', 'corp', 'corporation', 'company', 'title',
 ]);
 const SOFT_NONNAME_WORDS = new Set([
   'who', 'we', 'are', 'our', 'your', 'the', 'and', 'about', 'us', 'meet', 'team',
diff --git a/src/pr/lib/taxonomy.js b/src/pr/lib/taxonomy.js
index f19324c1..00401556 100644
--- a/src/pr/lib/taxonomy.js
+++ b/src/pr/lib/taxonomy.js
@@ -135,6 +135,12 @@ function classifyTitle(exactTitle) {
   }
   let seniority = 'other';
   for (const [re, s] of SENIORITY_RULES) { if (re.test(t)) { seniority = s; break; } }
+  // Cody c4: bare senior titles ("Director", "EVP, California") classified dept=other
+  // and became invisible to the coverage gate — a senior title with no functional
+  // department IS a leadership contact per the spec.
+  if (department === 'other' && ['c_suite', 'evp_svp', 'vp', 'director', 'principal'].includes(seniority)) {
+    department = 'leadership';
+  }
   return { normalized_role, department, seniority };
 }
 
diff --git a/src/pr/services/people.js b/src/pr/services/people.js
index c40b4c00..b3958bce 100644
--- a/src/pr/services/people.js
+++ b/src/pr/services/people.js
@@ -38,6 +38,10 @@ async function create(data, { evidence, actor } = {}) {
   // the table through adapter-level gaps — validate humanness at the ONE chokepoint.
   // Manual admin entry may override with allow_nonstandard_name:true (audited).
   if (!isLikelyPersonName(full_name) && data.allow_nonstandard_name !== true) {
+    // Cody c4: silent rejection is unauditable data loss — leave a trail so false
+    // positives can be found and replayed.
+    await audit.log({ actor: actor || 'system', action: 'person.rejected', entity_type: 'person',
+      detail: { full_name, reason: 'not_a_person_name', organization_id: data.organization_id || null, exact_title: data.exact_title || null } });
     return { person: null, created: false, rejected: 'not_a_person_name', full_name };
   }
   const names = splitName(full_name);

← eaccaf1f role icons: 13-icon SVG vocabulary for all CRE user/role typ  ·  back to Rentv  ·  social console: /api/firm/:id proxy + firm→people drilldown, 3db0aeaf →