Open
Conversation
Adds a public, case-insensitive-unique `display_name` to users.
Settable at signup, on user creation, and updatable any time via
PATCH /user/{user_id}. Defaults to the user's id (left-padded to 3
chars) when none is provided. Validates length (3-30) and charset
(letters, numbers, hyphens, underscores) with descriptive errors.
Includes Alembic migration that backfills existing users and adds a
case-insensitive unique index on LOWER(display_name).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous "__pending__" placeholder collided on the LOWER(display_name) unique index when two signups without a display_name ran concurrently, surfacing as a misleading DuplicateDisplayNameError. Use a per-insert random suffix instead. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #875.
Summary
display_namefield to users.PATCH /user/{user_id}(also accessible to admins withUSER_CREATE_UPDATE).-,_) with descriptive error messages, and surfaces a clean conflict message on duplicates.7->"007") when none is provided. Padding ensures existing users with id < 100 still satisfy the 3-char minimum.GET /user/{user_id}(v2 + v3) responses.Migration
alembic/versions/c4a3f8e1d75b_add_user_display_name.py:users.display_name VARCHAR(30) NOT NULL, backfills existing rows withLPAD(id::text, 3, '0'), and creates a unique functional index onLOWER(display_name)(CITEXT-equivalent without the extension).pending_users.display_nameso the chosen handle can be carried through the email-validation step.Tests added (
tests/integration/user/display_name/test_display_name.py)test_signup_with_display_name_persists_ittest_signup_without_display_name_defaults_to_padded_user_idtest_signup_rejects_display_name_too_shorttest_signup_rejects_display_name_too_longtest_signup_rejects_display_name_with_invalid_characterstest_signup_rejects_duplicate_display_name_case_insensitivetest_patch_updates_display_nametest_patch_rejects_display_name_too_shorttest_patch_rejects_display_name_with_invalid_characterstest_patch_rejects_duplicate_display_name_case_insensitivetest_patch_allows_setting_same_display_name_idempotentlytest_user_profile_response_includes_display_nameFollow-ups deferred (per the issue)
Test plan
uv run pytest tests/integration/user tests/integration/auth tests/integration/oauth(47 passed)uv run pytest tests(282 passed)uv run ruff check .uv run basedpyright --level error(0 errors)