Skip to content

STF-1906: Add phone verification inputs - #475

Merged
horgh merged 5 commits into
mainfrom
greg/billing-phone-verification-inputs
Oct 20, 2026
Merged

horgh merged 5 commits into
mainfrom
greg/billing-phone-verification-inputs

Conversation

@oschwald

@oschwald oschwald commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Adds three optional inputs to the /billing and /shipping request objects: phone_verification_method (delivered_code, network, or other), phone_was_verification_successful (boolean), and phone_verification_time (RFC 3339 date-time). They describe the most recent verification of the phone number. Both objects share one validation schema, and each value is checked.

The second commit makes the RFC 3339 check, which /event/time also uses, reject what the web service rejects: impossible dates and times such as 2026-02-30T25:61:61Z, offsets of 24 hours or more, and a lowercase t or z.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Billing and shipping requests can include a phone verification method, timestamp, and success status.
  • Bug Fixes
    • Timestamp validation now rejects impossible dates and times, lowercase separators, and timezone offsets of 24 hours or more.
  • Documentation
    • Updated request examples to show phone verification details for billing and shipping.

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 3236dc4b-ecd9-462e-8ff6-c98ba0a29024
📥 Commits

Reviewing files that changed from the base of the PR and between 2e99c0c and 12450c7.

📒 Files selected for processing: 3
  • HISTORY.rst
  • src/minfraud/validation.py
  • tests/test_validation.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

The transaction address schema now accepts phone-verification method, timestamp, and success-status fields for billing and shipping. RFC 3339 validation for event and phone-verification timestamps rejects impossible dates and times, lowercase t or z, and offsets of 24 hours or more.

Changes: Phone Verification and Timestamp Validation

Layer / File(s) Summary
RFC 3339 timestamp validation
src/minfraud/validation.py, tests/test_validation.py, HISTORY.rst
Timestamp validation checks calendar and clock values, uppercase T and Z, and offsets from 00:00 through 23:59. Shared test cases cover event and phone-verification timestamps.
Address phone-verification fields
src/minfraud/validation.py, tests/test_validation.py, tests/data/full-transaction-request.json, README.rst, HISTORY.rst
Billing and shipping schemas accept phone-verification method, timestamp, and boolean success-status fields. Tests and examples include these fields.

Priority: ⬇️ Low

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

Change: Feature

Suggested reviewers: horgh

Merge Risk: ⚪ Minimal · up to 12450

Billing and shipping accept the optional phone-verification fields consistently, and timestamps reject malformed formats and impossible dates or times. The remaining server range and length limitations are disclosed; no material merge risk was identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 2 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: adding phone verification inputs to the billing and shipping request objects.
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 2 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

A rabbit checks the dates at night
And stamps each phone detail just right
Billing, shipping fields appear
The clock rejects a leap too queer
The bunny hops, the tests shine bright!

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

@oschwald
oschwald force-pushed the greg/billing-phone-verification-inputs branch from 2792b9a to a28ab6c Compare October 12, 2026 14:56
@oschwald oschwald changed the title Add billing phone verification inputs Add phone verification inputs Oct 12, 2026
oschwald and others added 2 commits October 15, 2026 22:03
Add the optional phone_verification_method,
phone_was_verification_successful, and phone_verification_time inputs
to both the /billing and /shipping request objects. They describe the
most recent verification of the phone number. Both objects share the
same validation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The RFC 3339 check used only a regex. It accepted values that the web
service rejects, such as 2026-02-30T25:61:61Z or an offset of +24:00.
The check now uses the server's regex with an uppercase T and Z only,
then parses the date and time to reject impossible values. This
applies to /event/time and phone_verification_time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@oschwald
oschwald force-pushed the greg/billing-phone-verification-inputs branch from a28ab6c to 2e99c0c Compare October 15, 2026 22:04
@oschwald
oschwald marked this pull request as ready for review October 15, 2026 22:04
Copilot AI balanced review requested due to automatic review settings October 15, 2026 22:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@oschwald oschwald changed the title Add phone verification inputs STF-1906: Add phone verification inputs Oct 16, 2026

@horgh horgh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, with Claude nits

"phone_country_code": _telephone_country_code,
"phone_number": str,
"phone_verification_method": _phone_verification_method,
"phone_verification_time": _rfc3339_datetime,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

phone_verification_time uses the shared _rfc3339_datetime validator, so the client does not check the range in the spec: from the Unix epoch to two days in the future.

validate_transaction({"billing": {"phone_verification_time": "1969-12-31T23:59:59Z"}}) passes, and so does "2099-01-01T00:00:00Z". The server (validatePhoneVerificationTime) rejects both with PHONE_VERIFICATION_TIME_OUT_OF_RANGE, ignores the field, and scores the transaction without the signal. The caller gets no error.

The lower bound does not depend on the clock, so the client can check it with no clock-skew risk. The upper bound depends on the client clock, so skipping it is defensible, but the decision should be the same in all the sibling client PRs. The client also does not check the one-year range for /event/time, so if the intent is "format only, no range", the changelog should say that (see the HISTORY.rst comment).

🤖 Comment by Claude Opus 5.5.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No client checks this range, the same as for /event/time. The web service ignores a time outside the range and returns a warning. cf3ab80 changes the HISTORY entry, so it no longer says that the check matches the web service.

Reply by Claude Opus 5.5 on Greg's behalf.

Comment thread HISTORY.rst Outdated
inputs to the ``/billing`` and ``/shipping`` request objects. They describe
the most recent verification of the phone number.
* The RFC 3339 check on ``/event/time`` and ``phone_verification_time`` now
rejects the same values as the web service. It rejects impossible dates

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"rejects the same values as the web service" is not correct. The client still accepts values that the server rejects:

  • phone_verification_time before the Unix epoch or more than two days in the future.
  • event.time outside the server range (for example 2015-05-08T16:07:56Z, which is in GOOD_TIMES).
  • Strings longer than 255 characters (see the comment on the fraction group).

Suggest wording such as "now rejects more invalid values, such as ...", or add the missing checks.

🤖 Comment by Claude Opus 5.5.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pedantic.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworded in cf3ab80. It now says that the check rejects more values that the web service rejects.

Reply by Claude Opus 5.5 on Greg's behalf.


_rfc3339_datetime = All(
Match(
r"(?a)\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fraction group (\.\d+)? has no length limit. The server calls getString(v, 255, false) before it parses the time, so it rejects a value longer than 255 characters.

"2026-10-01T14:30:00." + "1" * 300 + "Z" passes validate_transaction for event.time and phone_verification_time. The server rejects it with "the string is too long" and ignores the field. This is an edge case, but it conflicts with the changelog claim. A bound such as (\.\d{1,9})? (nanosecond precision, which Go keeps) would close it.

🤖 Comment by Claude Opus 5.5.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will leave this. It is an edge case, and the HISTORY entry no longer claims a full match.

Reply by Claude Opus 5.5 on Greg's behalf.

Comment thread tests/test_validation.py
BAD_TIMES = (
"2015-05-08T16:07:56",
"2015-05-08 16:07:56Z",
"2026-02-30T25:61:61Z",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No BAD_TIMES case tests only an impossible day of the month. 2026-02-30T25:61:61Z also has hour 25 and minute and second 61, and 2026-13-45T10:00:00Z has month 13. Either one fails on the other fields first.

If _datetime_exists checked only field ranges (day 1 to 31), February 30 would pass and all tests would still pass. Suggest adding cases such as 2026-02-30T10:00:00Z, 2025-02-29T00:00:00Z (not a leap year) and 2026-04-31T00:00:00Z, so the "February 30" behavior in the changelog has a test.

🤖 Comment by Claude Opus 5.5.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 4f6a9b1.

Reply by Claude Opus 5.5 on Greg's behalf.

Comment thread src/minfraud/validation.py Outdated
def _datetime_exists(s: str) -> str:
# Reject impossible values such as Feb 30 or 24:00. The regex already
# checked the fraction and the offset, so parse only the part before them.
datetime.strptime(s[:19], "%Y-%m-%dT%H:%M:%S") # noqa: DTZ007

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: when strptime raises ValueError, voluptuous replaces it with a generic message:

Invalid transaction data: not a valid value for dictionary value @ data['event']['time']

The caller does not learn that the date or time is impossible. A regex failure at least shows the pattern. Raising voluptuous.Invalid("invalid date or time") here would give a useful message.

🤖 Comment by Claude Opus 5.5.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 12450c7. The error is now "invalid date or time".

Reply by Claude Opus 5.5 on Greg's behalf.

Comment thread tests/test_validation.py
def test_phone_was_verification_successful(self) -> None:
self.check_bool(self.type, "phone_was_verification_successful")

def test_phone_verification_time(self) -> None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this test covers only string inputs. test_phone_verification_method tests the int 1, but no test shows that a value that is not a string is rejected here, for example 1 or datetime(2026, 10, 1, tzinfo=UTC).

A Python caller can easily pass a datetime. Match rejects it now, but if a later change puts _datetime_exists first in All(...), s[:19] raises TypeError instead of a validation error, and no test fails.

🤖 Comment by Claude Opus 5.5.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 4f6a9b1.

Reply by Claude Opus 5.5 on Greg's behalf.

oschwald and others added 3 commits October 19, 2026 20:44
The client does not check the time ranges or the length limit of the web
service, so it does not reject every value that the web service rejects.
Say that it now rejects more of these values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add times that fail only on the calendar day. Also test that the int 1
and a datetime object are rejected for event.time and
phone_verification_time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Before, the error was "not a valid value".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 19, 2026 20:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@horgh
horgh merged commit a985539 into main Oct 20, 2026
50 checks passed
@horgh
horgh deleted the greg/billing-phone-verification-inputs branch October 20, 2026 21:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants