Skip to content

Backend: fix feature-flag gating gaps for SMS and postal verification - #8781

Merged
aapeliv merged 2 commits into
developfrom
backend/fix/feature-flag-gating-gaps
May 24, 2026
Merged

Backend: fix feature-flag gating gaps for SMS and postal verification#8781
aapeliv merged 2 commits into
developfrom
backend/fix/feature-flag-gating-gaps

Conversation

@aapeliv

@aapeliv aapeliv commented May 24, 2026

Copy link
Copy Markdown
Member

Follow-up to #8774, tightening up two places where the recently-migrated feature flags weren't gating things correctly.

What & why

1. sms_enabled now gated at the ChangePhone RPC. Previously the flag was read globally (anonymous) inside send_sms, even though its only caller always has a user context. Two problems: global evaluation skips per-user feature-usage tracking and would silently fall through to default=False if the flag ever became a rollout/experiment; and gating deep in a util was inconsistent with every other flag. Now ChangePhone checks sms_enabled per-user and aborts UNAVAILABLE + translatable sms_disabled, matching donations/postal_verification/strong_verification. send_sms is back to a pure sender. Removing a phone number stays ungated (it sends no SMS).

2. postal_verification_enabled only gated the free step. Only InitiatePostalVerification (address validation) checked the flag. ConfirmPostalAddress — the step that queues the actual (paid) postcard — did not, so a user already past step 1 could still trigger a postcard with the flag turned off. Now ConfirmPostalAddress is gated too, consistent with initiation.

Deliberately left as-is

  • recaptcha_enabled (per-user, but AntiBot/AntiBotPolicy serve logged-out signup traffic): per-user is already the most-correct choice; anonymous users can't be bucketed, so this is a config concern (use an unconditional force rule, not a % rollout, to cover logged-out users) rather than a code bug.
  • check_mypostcard_jobs (global eval): it's a fleet-wide monitoring job with genuinely no per-user context, so global is the documented-correct path.

Testing

  • New test_postal_verification_confirm_disabled asserts ConfirmPostalAddress aborts UNAVAILABLE when the flag is off (seeds a pending attempt directly, since initiation is gated by the same flag).
  • New test_ChangePhone_sms_disabled asserts setting a number aborts UNAVAILABLE when sms_enabled is off, and that removing a number is still allowed.
  • uv run pytest src/tests/test_verification.py src/tests/test_postal_verification.py src/tests/test_experimentation.py src/tests/test_account.py — all pass.
  • make format clean. make mypy has two pre-existing errors in untouched files (tests/fixtures/misc.py, test_calendar_events.py), unrelated to this change.

Backend checklist

  • Added tests for any new code or added a regression test if fixing a bug
  • Run the backend locally and it works
  • Added migrations if there are any database changes, rebased onto develop if necessary for linear migration history

For maintainers

  • Maintainers can push commits to my branch
  • Maintainers can merge this PR for me

🤖 Generated with Claude Code

Evaluate sms_enabled per-user instead of globally - send_sms always has a
user in scope (its only caller, ChangePhone, has the context), so global
evaluation skipped feature-usage tracking and would silently fall through to
the default if the flag ever became a rollout/experiment.

Gate ConfirmPostalAddress on postal_verification_enabled. Previously only the
free address-validation step (InitiatePostalVerification) was gated, so a user
already past step 1 could still trigger a (paid) postcard with the flag off.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vercel

vercel Bot commented May 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
couchers Ready Ready Preview May 24, 2026 1:25am

Request Review

Move the sms_enabled check to the servicer, consistent with every other
feature flag (donations, postal verification, strong verification, recaptcha).
ChangePhone now aborts UNAVAILABLE with a translatable "sms_disabled" error
rather than send_sms returning a magic string surfaced as UNIMPLEMENTED.
send_sms goes back to a pure sender. Removing a phone number stays ungated
since it sends no SMS.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@aapeliv
aapeliv requested a review from tristanlabelle as a code owner May 24, 2026 01:22
@aapeliv
aapeliv merged commit 96de3e2 into develop May 24, 2026
6 checks passed
@aapeliv
aapeliv deleted the backend/fix/feature-flag-gating-gaps branch May 24, 2026 01:45
@github-actions

Copy link
Copy Markdown
Contributor

📝 Release Notes

This PR does not need to be included in release notes.

Reason: This is a backend follow-up that fixes internal feature-flag gating for SMS and postal verification. It mainly affects admin-controlled enable/disable behavior and edge cases when features are turned off, rather than adding new functionality or a broadly noticeable user-facing change. While it prevents verification actions from slipping through when disabled, this is too implementation-specific and limited to merit release notes.

🤖 Bot Debug Information

Model: couchers.openai.gpt-5.4
Decision: exclude
Reasoning: This is a backend follow-up that fixes internal feature-flag gating for SMS and postal verification. It mainly affects admin-controlled enable/disable behavior and edge cases when features are turned off, rather than adding new functionality or a broadly noticeable user-facing change. While it prevents verification actions from slipping through when disabled, this is too implementation-specific and limited to merit release notes.

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.

1 participant