# reference agent emailed the same reference twice - the dedup key was candidate_id, not candidate_id plus reference email

## TL;DR

The dedup key was candidate_id, so the second reference for the same candidate sailed through as 'new'. Key dedup on candidate plus reference email: one row per (candidate, reference) pair. Dedup keys must capture what 'duplicate' actually means.

```text
reference agent emailed same reference twice - dedup key was candidate_id only
```

## Steps

1. Confirm the dedup gap: check the sent log for the same reference email under one candidate.
   Expected: The duplicate is visible.

2. Change the dedup key to (candidate_id, reference_email), normalized and lowercased.
   Expected: The pair is unique.

3. Apologize to the double-contacted references; being asked twice looks disorganized.
   Expected: The incident is owned.

4. Backfill the dedup store with the composite keys for in-flight reference checks.
   Expected: In-flight dupes are prevented.

5. Add a test: two references for one candidate must both send; the same reference twice must not.
   Expected: The key is enforced.

## When to use

- the same reference is contacted twice
- dedup keys on candidate only
- multiple references per candidate

## When not to use

- the two contacts were intentional (different roles, different asks; then it is not a dupe)
- references are contacted once by design already (check the send log for the real cause)
- the duplicate came from a retry, not dedup (fix idempotency instead)

## Tool compatibility

- any reference-check workflow
- dedup key design

## Variant phrasings

- "reference emailed twice dedup"
- "duplicate reference contact"
- "dedup key candidate_id only"

## Why it happens

Dedup keys define identity, and candidate_id identifies the candidate, not the outreach. Two references for one candidate are two distinct outreach targets sharing a candidate_id, so the key let the second through. The key must match the unit of work: one email to one reference about one candidate.

## Edge cases

- normalize emails before keying; case and plus-addressing create false distincts
- the same reference for two candidates is two legitimate outreach targets
- retries need idempotency keys separate from dedup keys

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_JyUVxDlEqVvXi0nF3aUV6w
