Adopt 'username' over 'handle' in default OAuth/login copy #80

Closed
opened 2026-07-29 17:28:24 +00:00 by claude-bot · 2 comments
Collaborator

Summary

Follow-up to #32, same shape of change and the same reasoning one layer down. #32 replaced AT Protocol with Atmosphere in the default sign-in copy because the protocol's word for the network is not the word to put in front of a person. The other protocol word in that same form is handle — and every other site on the internet calls that field a username.

Somebody arriving at a login form has typed a username a thousand times and a handle never. "Handle" is a term the reader has to be taught before the form makes sense, and there is nothing it buys them once they have been: the value they type, the way it validates, and what happens next are all identical. Bluesky's own onboarding has been drifting the same way. We're switching the copy in Ponente (the app this SDK's LoginForm renders in) and would rather not diverge from the SDK's defaults to do it — hence canonicalizing it here.

What ships as "handle" today

In ATProtoNet.Blazor 0.5.0, the user-visible defaults are:

  • LoginForm's field label — "Handle"
  • its hint — "Your Atmosphere account handle"
  • the /atproto/login error text — "The 'handle' query parameter is required. Example: /atproto/login?handle=alice.bsky.social" (this one is developer-facing, so it can keep the protocol's word)

Suggested change

Defaults only, in the strings a person reads:

  • label → "Username"
  • hint → "Your Atmosphere account username"

Explicitly not asking for a rename of anything below the copy. HandleLabel / HandlePlaceholder / HandleHint, the handle query parameter, the atproto-handle input id, IsHandleVerified, HandleResolutionTimeout and everything else on the wire or in the API should stay as they are — that is the protocol's vocabulary, it matches the specification and the lexicons, and renaming it would be a breaking change that buys nobody anything. This is the same split #32 landed on: Atmosphere in the copy, ATProto in the code.

If a rename of the parameters is ever wanted for symmetry, UsernameLabel etc. as aliases forwarding to the existing ones would do it without a break — but the defaults are the part that matters, since an app that doesn't override them is the one shipping the word.

Why it's worth doing upstream

A consumer can already override all three parameters (Ponente does). But then every app that doesn't override ships "Handle", every app that does picks its own wording, and the ecosystem gets the fragmentation #32 was about. The default is what most apps ship.

(Filed by the Ponente bot alongside Grandiras/Ponente#65, which makes the same switch app-side.)

## Summary Follow-up to #32, same shape of change and the same reasoning one layer down. #32 replaced *AT Protocol* with **Atmosphere** in the default sign-in copy because the protocol's word for the network is not the word to put in front of a person. The other protocol word in that same form is **handle** — and every other site on the internet calls that field a **username**. Somebody arriving at a login form has typed a username a thousand times and a handle never. "Handle" is a term the reader has to be taught before the form makes sense, and there is nothing it buys them once they have been: the value they type, the way it validates, and what happens next are all identical. Bluesky's own onboarding has been drifting the same way. We're switching the copy in Ponente (the app this SDK's `LoginForm` renders in) and would rather not diverge from the SDK's defaults to do it — hence canonicalizing it here. ## What ships as "handle" today In `ATProtoNet.Blazor` 0.5.0, the user-visible defaults are: - `LoginForm`'s field label — **"Handle"** - its hint — **"Your Atmosphere account handle"** - the `/atproto/login` error text — *"The 'handle' query parameter is required. Example: /atproto/login?handle=alice.bsky.social"* (this one is developer-facing, so it can keep the protocol's word) ## Suggested change Defaults only, in the strings a person reads: - label → **"Username"** - hint → **"Your Atmosphere account username"** **Explicitly not asking for a rename of anything below the copy.** `HandleLabel` / `HandlePlaceholder` / `HandleHint`, the `handle` query parameter, the `atproto-handle` input id, `IsHandleVerified`, `HandleResolutionTimeout` and everything else on the wire or in the API should stay as they are — that is the protocol's vocabulary, it matches the specification and the lexicons, and renaming it would be a breaking change that buys nobody anything. This is the same split #32 landed on: Atmosphere in the copy, ATProto in the code. If a rename of the *parameters* is ever wanted for symmetry, `UsernameLabel` etc. as aliases forwarding to the existing ones would do it without a break — but the defaults are the part that matters, since an app that doesn't override them is the one shipping the word. ## Why it's worth doing upstream A consumer can already override all three parameters (Ponente does). But then every app that doesn't override ships "Handle", every app that does picks its own wording, and the ecosystem gets the fragmentation #32 was about. The default is what most apps ship. (Filed by the Ponente bot alongside https://git.grandiras.net/Grandiras/Ponente/issues/65, which makes the same switch app-side.)
Author
Collaborator

🤖 On it — follow along in the action run; the reply will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the task runs.

🤖 On it — follow along in [the action run](https://git.grandiras.net/Grandiras/claude-bot/actions/runs/162); the reply will link the full session transcript. 📜 [Live transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/ATProto.NET/issue-80/run-162.md) — updating every ~5 minutes while the task runs.
Author
Collaborator

Done — pushed to claude/issue-80 (commit 7dbb26e).

What changed

Defaults only, in src/ATProtoNet.Blazor/Components/LoginForm.razor:

before after
HandleLabel default "Handle" "Username"
HandleHint default "Your Atmosphere account handle — your PDS is detected automatically." "Your Atmosphere account username — your PDS is detected automatically."

HandlePlaceholder (alice.bsky.social) is unchanged — it's an example value, not a word for the field.

Nothing below the copy moved, as the issue asked: HandleLabel/HandlePlaceholder/HandleHint keep their names (so the IStringLocalizer<LoginForm> resource keys keep working unchanged too), as do the handle query parameter, the atproto-handle input id, IsHandleVerified, and HandleResolutionTimeout. The /atproto/login error text in AtProtoAuthenticationExtensions.cs:114 still says 'handle' query parameter — it names the parameter and is developer-facing. No aliases were added; the issue framed those as optional and they'd be new public surface for no default-copy benefit.

Also updated: the two XML doc summaries stating the defaults, the parameter table and terminology note in docs/blazor.md, and a Changed bullet in CHANGELOG.md under [Unreleased] flagging that apps asserting on the old strings in UI/screenshot tests need to update expectations.

Verified

  • dotnet build -p:EnableSourceControlManagerQueries=false — succeeded, 0 warnings, 0 errors (this repo builds CS1591 as an error, so the doc-comment edits are checked).
  • dotnet test tests/ATProtoNet.Tests/ -p:EnableSourceControlManagerQueries=false1162 passed, 0 failed, 5 skipped (the usual Aspire-manifest gated tests).

One note: no test asserts on LoginForm's rendered copy, so the defaults aren't covered by the suite in either direction — the build and test runs confirm the change compiles and breaks nothing, not that the rendered label reads "Username". I read the render path (LoginForm.razor:25 and :32 bind EffectiveHandleLabel/EffectiveHandleHint, whose fallbacks are the strings above) to confirm that by inspection. Happy to add a bUnit-style render test if you want the copy pinned.


⏱ 2m 45s · 26 turns · tokens: 35.7k in / 7.0k out (+969.3k cache-read)
📜 Full session transcript
→ Opened PR: #81

Done — pushed to **`claude/issue-80`** (commit `7dbb26e`). ## What changed Defaults only, in `src/ATProtoNet.Blazor/Components/LoginForm.razor`: | | before | after | |---|---|---| | `HandleLabel` default | `"Handle"` | `"Username"` | | `HandleHint` default | `"Your Atmosphere account handle — your PDS is detected automatically."` | `"Your Atmosphere account username — your PDS is detected automatically."` | `HandlePlaceholder` (`alice.bsky.social`) is unchanged — it's an example value, not a word for the field. Nothing below the copy moved, as the issue asked: `HandleLabel`/`HandlePlaceholder`/`HandleHint` keep their names (so the `IStringLocalizer<LoginForm>` resource keys keep working unchanged too), as do the `handle` query parameter, the `atproto-handle` input id, `IsHandleVerified`, and `HandleResolutionTimeout`. The `/atproto/login` error text in `AtProtoAuthenticationExtensions.cs:114` still says `'handle' query parameter` — it names the parameter and is developer-facing. No aliases were added; the issue framed those as optional and they'd be new public surface for no default-copy benefit. Also updated: the two XML doc summaries stating the defaults, the parameter table and terminology note in `docs/blazor.md`, and a `Changed` bullet in `CHANGELOG.md` under `[Unreleased]` flagging that apps asserting on the old strings in UI/screenshot tests need to update expectations. ## Verified - `dotnet build -p:EnableSourceControlManagerQueries=false` — succeeded, **0 warnings, 0 errors** (this repo builds CS1591 as an error, so the doc-comment edits are checked). - `dotnet test tests/ATProtoNet.Tests/ -p:EnableSourceControlManagerQueries=false` — **1162 passed, 0 failed, 5 skipped** (the usual Aspire-manifest gated tests). One note: no test asserts on `LoginForm`'s rendered copy, so the defaults aren't covered by the suite in either direction — the build and test runs confirm the change compiles and breaks nothing, not that the rendered label reads "Username". I read the render path (`LoginForm.razor:25` and `:32` bind `EffectiveHandleLabel`/`EffectiveHandleHint`, whose fallbacks are the strings above) to confirm that by inspection. Happy to add a bUnit-style render test if you want the copy pinned. --- ⏱ 2m 45s · 26 turns · tokens: 35.7k in / 7.0k out (+969.3k cache-read) 📜 [Full session transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/ATProto.NET/issue-80/run-162.md) → Opened PR: https://git.grandiras.net/Grandiras/ATProto.NET/pulls/81
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Grandiras/ATProto.NET#80
No description provided.