feat(leads): normalize lead phone numbers to E.164 (create & update)#202
Conversation
Best-effort US E.164 normalization (fail-safe: unrecognized/intl/empty pass through unchanged, so a lead is never dropped). Applied on both create_lead and update_lead so the "stored phones are normalized" invariant survives admin CRM edits, not just first capture. Makes click-to-call, SMS, and dedup-grouping reliable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e0f17224a2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| digits = re.sub(r"\D", "", phone) | ||
| if len(digits) == 10: | ||
| return f"+1{digits}" |
There was a problem hiding this comment.
Preserve non-US international numbers before adding +1
For international inputs that already include a non-US country code but happen to contain exactly 10 digits, this strips the + and rewrites the number as a US number. For example, +64 9 123 4567 becomes +16491234567 instead of being left unchanged as promised, so a valid lead phone can be corrupted and become uncallable; check for an explicit +/non-1 country code before the 10-digit US fallback.
Useful? React with 👍 / 👎.
What
Best-effort E.164 normalization for US lead phone numbers, applied on both
create_leadandupdate_leadinlead_management.py.(281) 324-3020,281-324-3020,2813243020,1 (281) 324-3020→+12813243020Why
Consistent E.164 storage makes click-to-call, SMS, and dedup-grouping reliable across the CRM and the Notion Lead Pipeline mirror. Covering
update_lead(not justcreate_lead) keeps the "stored phones are normalized" invariant intact when an admin edits a lead.Safety
Noneinputs pass through unchanged — a lead is never dropped or mangled.update_lead'smerge=True).to_dict()/asdict()), sofrom_dict()round-trips correctly.Tests
New
tests/test_lead_phone_normalize.py(4 tests): US-format canonicalization, idempotency, never-loses-data, and both the create and update persistence paths.Full suite: 843 passed, 0 failed locally.
🤖 Generated with Claude Code