Conversation
…tcher (career-ops-hq#2671) checkRoleMatch() treated any role-title word longer than 3 characters as a sufficient match on its own, with no requirement that a second signal (company name or sender domain) also corroborate it. A tracker row titled "Talent Acquisition Specialist" splits into ["Talent","Acquisition", "Specialist"], and any unrelated email containing just one of those words anywhere (e.g. in a different recruiter's signature line) satisfied the match and got misattributed to that application. Two changes: - Add checkRoleMatchExact(), which only credits a match on the *entire* role title (or its Chinese symbol-stripped form) as a contiguous substring. This is specific enough to stand alone. A role that is a single generic word (e.g. "Recruiter") is excluded from this path too, since a whole-role check degenerates into a bare-word check for single-word titles. - matchCandidates() now only counts a partial (significant-word) role match when it is corroborated by checkCompanyMatch or a sender-domain match already computed for that application. checkRoleMatch() also gains a stoplist (GENERIC_ROLE_WORDS) of generic recruiting/HR vocabulary that never counts as a significant word by itself, regardless of length. checkCompanyMatch, exact/near-exact role matches, and Chinese role-title handling are unchanged. Closes career-ops-hq#2671
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe matcher adds exact role-title matching, filters generic recruiting terms from partial matches, and requires company-name or sender-domain corroboration for partial candidate matches. Tests cover generic, exact, corroborated partial, sender-domain, and standalone specific role matches. ChangesRole matching
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@reply-matcher.mjs`:
- Around line 69-75: Update checkRoleMatchExact in reply-matcher.mjs to reject
single-word role titles before the normalized substring check, while preserving
the existing Chinese-title behavior for determining whether a role is
single-word. In reply-matcher.test.mjs lines 61-70, add a regression assertion
confirming that a non-generic single-word role such as Engineer does not qualify
as an exact standalone match.
In `@reply-matcher.test.mjs`:
- Around line 319-340: Add a separate test near the existing partial role-match
case that omits the company name from the candidate message, supplies the sender
domain through the getAppDomains input to match the application, and retains
only a partial specific role match. Assert the result includes role-title and
has high confidence, without asserting company-name.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: bede1f8f-4d56-41d0-98cb-bb275ece27bf
📒 Files selected for processing (2)
reply-matcher.mjsreply-matcher.test.mjs
…bit review on career-ops-hq#2672) Addresses two CodeRabbit findings on PR career-ops-hq#2672: 1. Major — checkRoleMatchExact() only excluded single-word roles that were also generic stoplist words (isBareGenericRole), so a specific single-word role like "Engineer" still qualified as a standalone exact match against any message containing that word anywhere, recreating the uncorroborated false-positive path the PR was meant to close. Replaced isBareGenericRole with isSingleWordRole: any role that reduces to a single word — generic or not — now falls through to the partial-match path and requires company/domain corroboration in matchCandidates(), same as any other single significant word. Chinese compound titles (which carry no separators to split on) are explicitly exempted via a CJK check, preserving the existing Chinese-title exact-match behavior. 2. Minor — added a matchCandidates test exercising sender-domain corroboration on its own (no company-name text in the message), since the existing corroboration test only covered the company-name path. Also added a regression test proving Chinese single-part titles still match exactly, and one confirming checkRoleMatch's boolean convenience path still reports a match for a single-word role — it's matchCandidates that enforces corroboration, not checkRoleMatch itself.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@reply-matcher.mjs`:
- Around line 80-82: Update checkRoleMatchExact to normalize role before
matching and return false when the normalized role is empty, including
whitespace-only titles; preserve the existing single-word rejection and add a
regression test covering a whitespace-only role.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 34f0b6af-f92f-452e-8e3b-30757298757d
📒 Files selected for processing (2)
reply-matcher.mjsreply-matcher.test.mjs
…Rabbit review on career-ops-hq#2672) normalizeStr(' ') === '', and String.prototype.includes('') is always true, so a whitespace-only role title (e.g. " ") produced a false "exact" match against any text at all, bypassing the corroboration requirement entirely. isSingleWordRole doesn't catch this case: splitting a whitespace-only string on separators yields zero parts, not one. Added an explicit rNorm-empty guard in checkRoleMatchExact and a regression test confirming a whitespace-only role never matches arbitrary text.
|
Merged, @Schlaflied. A partial title match on its own is weak evidence — "Engineer" appears in half an inbox — and treating it as sufficient is how a reply gets attached to the wrong application, which is worse than not matching at all: the row looks handled and the real thread stays invisible. Requiring corroboration before acting on a partial is the right threshold. Closes #2671. |
Summary
checkRoleMatch()treated any role-title word longer than 3 characters as sufficient evidence of a match on its own, with no requirement that a second signal (company name or sender domain) also corroborate it. A tracker row titled e.g. "Talent Acquisition Specialist" splits into["Talent","Acquisition","Specialist"], and any unrelated email containing just one of those words anywhere — such as a different recruiter's signature line ("Talent Acquisition & Diversity") for a completely different company — satisfied the match and got misattributed to that application.checkRoleMatchExact(), which only credits a match on the entire role title (or its Chinese, symbol-stripped form) as one contiguous substring. That's specific enough to stand alone. A role that's a single generic word (e.g.role: "Recruiter") is excluded from this path too, since a whole-role check degenerates into a bare-word check when there's no multi-word phrase to be specific about.matchCandidates()now only counts a partial (significant-word) role match when it's corroborated bycheckCompanyMatchor the sender-domain match, both already computed per-application in that loop.checkRoleMatch()also gainsGENERIC_ROLE_WORDS, a stoplist of generic recruiting/HR vocabulary (talent, acquisition, specialist, coordinator, operations, recruiter, recruiting, human, resources, people) that never counts as a significant word by itself, regardless of length — these are exactly the words most likely to collide with unrelated senders' signatures/titles.Non-goals / guarantees preserved
checkCompanyMatch, exact/near-exact role matches, and Chinese role-title handling are unchanged.no-match/ambiguous-matchhandling inmatchCandidates.Test plan
node --test reply-matcher.test.mjs— all passing, including new regression coverage:checkRoleMatch - generic recruiting words never match alone (#2671)checkRoleMatchExact - only a full contiguous role-title match countsmatchCandidates - a generic role-title word from an unrelated sender does not match (#2671)matchCandidates - a partial role-word match corroborated by company name still matchesmatchCandidates - a genuinely specific role match still works standalonenode test-all.mjs— 3276 passed, 0 failed (1 pre-existing warning, unrelated to this change)Closes #2671
Summary by CodeRabbit
Bug Fixes
Tests