Skip to content

Strong Verification failure message can't tell users whether birthdate or gender mismatched #9174

Description

@claude

Problem

When a Strong Verification attempt fails because the passport data doesn't match the user's profile, we show a single combined message that mentions both date of birth and gender:

Your Strong Verification attempt has failed because the date of birth or gender on your profile does not match the date of birth or sex on your passport. Please contact the support team to update your date of birth or gender, or if your passport sex does not match your gender identity.

Because this message can't tell the user which field actually mismatched, some users contact support confused about why their verification failed (raised in the email copy review in #9150, on app/backend/src/couchers/email/locales/en.json).

Why it's a catch-all today

In app/backend/src/couchers/jobs/handlers.py we only check the combined predicate has_strong_verification(user) and, on failure, emit a single reason:

else:
notify(
session,
user_id=verification_attempt.user_id,
topic_action=NotificationTopicAction.verification__sv_fail,
key="",
data=notification_data_pb2.VerificationSVFail(
reason=notification_data_pb2.SV_FAIL_REASON_WRONG_BIRTHDATE_OR_GENDER
),
)

else:
    notify(
        session,
        user_id=verification_attempt.user_id,
        topic_action=NotificationTopicAction.verification__sv_fail,
        key="",
        data=notification_data_pb2.VerificationSVFail(
            reason=notification_data_pb2.SV_FAIL_REASON_WRONG_BIRTHDATE_OR_GENDER
        ),
    )

has_strong_verification is defined as the AND of the birthdate and gender checks, so by the time we reach the else we've thrown away which one failed:

# couchers/models/verification.py
def has_strong_verification(self, user):
    return self.is_valid & self._raw_birthdate_match(user) & self._raw_gender_match(user)

Good news

The model already exposes the granular checks matches_birthdate(user) and matches_gender(user) (in couchers/models/verification.py), so we can distinguish the cause without new data:

def matches_birthdate(self, user): return self.is_valid & self._raw_birthdate_match(user)
def matches_gender(self, user):    return self.is_valid & self._raw_gender_match(user)

Proposed fix

  • In the failure branch, evaluate matches_birthdate / matches_gender separately and pick a more specific SV_FAIL_REASON_* (e.g. wrong birthdate vs. wrong gender; possibly keep the combined reason only for the both-wrong case).
  • Add the corresponding reason enum value(s) to the VerificationSVFail proto.
  • Split the email/notification copy into separate, targeted messages (the email copy review noted this should be a follow-up, not part of Backend/emails: Review copy before localizing #9150).

Notes / open questions

  • @aapeliv has the most context on the Strong Verification flow and whether there are edge cases (e.g. passport_sex == unspecified, the has_passport_sex_gender_exception escape hatch) that should still fall back to the combined message.
  • This affects more than just the email — push notifications and any other surface using SV_FAIL_REASON_WRONG_BIRTHDATE_OR_GENDER would need updating too.

Filed from a review discussion in #9150.

Metadata

Metadata

Labels

1.topic backendThis issue relates to the python backend

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions