← back to Rentv 2026
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
M src/pr/lib/normalize.jsM src/pr/lib/taxonomy.jsM src/pr/services/people.js
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 2026
·
social console: /api/firm/:id proxy + firm→people drilldown, 3db0aeaf →