Skip to content

fix(merge-tracker): guard tier-3 fuzzy dedup with req/job numbers - #1525

Merged
santifer merged 1 commit into
santifer:mainfrom
Schlaflied:fix/merge-tracker-req-number-dedup
Jul 4, 2026
Merged

fix(merge-tracker): guard tier-3 fuzzy dedup with req/job numbers#1525
santifer merged 1 commit into
santifer:mainfrom
Schlaflied:fix/merge-tracker-req-number-dedup

Conversation

@Schlaflied

@Schlaflied Schlaflied commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #1524.

merge-tracker.mjs's tier-3 duplicate detection (company match + roleFuzzyMatch) had no req/job-number awareness. Two distinct postings at the same company with similarly-worded titles could collapse into a single tracker row whenever a req/job number in the free-text Notes column was the only thing actually distinguishing them — e.g. two L&D-type postings at the same employer with near-identical generic titles, different req numbers (R_1494379 vs R_1488728 in the reported case).

Fix

  • Added extractReqNumber(notes) in merge-tracker.mjs, which pulls a req/job/posting number out of a Notes cell.
  • Wired it into the tier-3 fuzzy-match block: if both sides of a fuzzy-matched candidate have an extractable number and the numbers differ, the candidate is treated as not a duplicate (falls through to "new entry" / keeps searching). If either side has no extractable number, today's fuzzy-match-only behavior is unchanged.

Req/job-number formats found in use

Grepped this project's own data/applications.md Notes column (not the three examples in the issue alone) to build the extraction regex against real formats rather than guessing:

  • R_1488728 (underscore prefix)
  • Req 1084, Req #1311, Req PRACT011038, Req SENIO001021 (bare/hash/alphanumeric)
  • REQ-056759, REQ-1000049295, REQ-2026-32061 (uppercase, hyphenated)
  • Job 202606-116491, Job #31786, Job ID 65136 (bare / hash / two-word "Job ID")
  • Posting ID 5340, Posting #114148, Posting 26-36
  • JR00124259, JR6497 (no separator)
  • Ref R2857957, Ref 2026-45698

extractReqNumber()'s regex covers all of these label prefixes (R_, Req/REQ/Requisition, JR, Job, Job ID, Posting, Posting ID, Ref/Reference) with a required trailing digit so it doesn't accidentally match unrelated words like "Required" or "Reference Program" that merely start with the same letters.

Edge case: number on only one side

The issue doesn't fully spec this. I chose to fall back to existing fuzzy-match behavior (still treat as a duplicate if the fuzzy match says so) — you can't prove a mismatch without both numbers, and the issue is explicit that the fix should only prevent false positives, never introduce new false negatives on cases that already work today.

Tests

Added a self-test block to test-all.mjs (mirroring the existing #751/#912 merge-tracker regression blocks, same temp-fixture pattern) covering:

  • (a) same-looking titles, different req numbers → NOT a duplicate, both rows survive
  • (b) same-looking titles, same req number → still a duplicate (lower score → skipped, no extra row)
  • (c) no req number on either side → existing fuzzy-match behavior unchanged (still deduped/updated)
  • (d) req number on only one side → falls back to fuzzy match, still deduped

All example/test data uses invented placeholder companies (Fabrikam, Northwind) — no real company names or personal job-search data.

Test plan

  • node test-all.mjs --quick — 1158 passed, 0 failed, 1 warning (pre-existing/expected warnings only — no rate-limit flake observed)
  • New req/job-number dedup self-test block passes all 4 cases (a)-(d)
  • Manually verified merge-tracker output against a debug fixture before finalizing assertions

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved duplicate handling in the tracker so similar entries with different request/job identifiers are no longer incorrectly merged.
    • Existing duplicate detection still works when identifiers match, and behavior now falls back safely when identifiers are missing on one or both sides.
    • Added coverage for key merge scenarios to help prevent regressions.

…ntifer#1524)

Tier-3 duplicate detection (company + fuzzy role match) had no
req/job-number awareness, so two distinct postings at the same company
with similarly-worded titles could collapse into one tracker row
whenever a req/job number in the Notes column was the only thing that
actually distinguished them (e.g. two L&D postings at the same company,
same-ish title, different req numbers).

Add extractReqNumber(), which pulls a req/job/posting number out of a
Notes cell using the label formats already in use in this project's own
applications.md (R_, REQ/Req, Requisition, JR, Job, Job ID, Posting,
Posting ID, Ref/Reference). Wire it into the tier-3 block: if both sides
of a fuzzy-matched candidate have an extractable number and the numbers
differ, the candidate is not treated as a duplicate. If either side has
no extractable number, today's fuzzy-match-only behavior is unchanged.

Adds a self-test block to test-all.mjs covering: different req numbers
(not a duplicate), same req number (still a duplicate), no req number on
either side (unchanged fuzzy-match behavior), and req number on only one
side (falls back to fuzzy-match, since a mismatch can't be proven).

Closes santifer#1524

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c7892bb2-030e-43d6-b40f-c40b611bbcf4

📥 Commits

Reviewing files that changed from the base of the PR and between ced5f74 and 439531d.

📒 Files selected for processing (2)
  • merge-tracker.mjs
  • test-all.mjs

📝 Walkthrough

Walkthrough

merge-tracker.mjs adds a regex-based helper to extract req/job/posting/reference identifiers from tracker Notes and uses it in tier-3 fuzzy company+role duplicate detection to prevent false duplicates when extracted numbers disagree. test-all.mjs adds a corresponding integration test.

Changes

Req/job-number dedup guard

Layer / File(s) Summary
Req number extraction and dedup guard
merge-tracker.mjs
Adds REQ_NUMBER_RE and extractReqNumber() to parse identifiers from Notes, and updates tier-3 fuzzy duplicate detection to require matching req numbers when both sides have them.
Dedup guard integration test
test-all.mjs
Adds a fixture-based test covering four cases: different req numbers (not deduped), same req numbers (deduped), no req numbers (existing fuzzy behavior), and one-sided req numbers (fuzzy fallback).

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

Possibly related PRs

  • santifer/career-ops#634: Both PRs modify the tier-3 duplicate detection logic in merge-tracker.mjs, with this retrieved PR changing the fuzzy role matching rules that the new guard depends on.
  • santifer/career-ops#793: Both PRs modify duplicate-detection/fuzzy role dedup behavior in merge-tracker.mjs with corresponding test-all.mjs coverage.
  • santifer/career-ops#1065: Both PRs add an extra extracted-identifier guard into merge-tracker.mjs's duplicate-detection flow with a matching regression test in test-all.mjs.

Suggested labels: 🔴 core-architecture

Suggested reviewers: amrskr4-arch, santifer

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding req/job-number guards to tier-3 fuzzy dedup in merge-tracker.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@santifer

santifer commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Nice guard, @Schlaflied — keying tier-3 fuzzy dedup on the req/job number stops two distinct same-company postings with near-identical titles from collapsing into one row, and it falls back to today's behavior byte-for-byte when either side lacks a number. Four targeted self-tests. Closes #1524. Merged! 🚀

@santifer
santifer merged commit fdb4376 into santifer:main Jul 4, 2026
10 checks passed
@github-actions github-actions Bot mentioned this pull request Jul 4, 2026
d-ulker pushed a commit to d-ulker/career-ops that referenced this pull request Jul 7, 2026
Schlaflied added a commit to Schlaflied/career-ops that referenced this pull request Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: merge-tracker.mjs fuzzy company+role dedup ignores req/job numbers, false-positive skips distinct postings

2 participants