Skip to content

Add invalid handle recovery dialog#11062

Draft
mozzius wants to merge 1 commit into
mainfrom
claude/invalid-handle-debug-menu-606t9b
Draft

Add invalid handle recovery dialog#11062
mozzius wants to merge 1 commit into
mainfrom
claude/invalid-handle-debug-menu-606t9b

Conversation

@mozzius

@mozzius mozzius commented Jul 3, 2026

Copy link
Copy Markdown
Member

When the signed-in account's handle comes back as handle.invalid, auto-open
a dialog (snoozed per account for 24h) that explains the problem and offers
a path to fix it:

  • Refresh button: asks the server to re-resolve identity via
    com.atproto.identity.refreshIdentity, then re-syncs the session
  • Server-resolution diagnostics: recovers the intended handle from the DID
    document (describeRepo alsoKnownAs) and resolves it to distinguish
    "resolves correctly now", "wrong DID", "not resolving", and
    service-provided handle issues
  • Static FAQ of likely causes (missing/multiple TXT records, wrong DID,
    expired domain, propagation delay, well-known file)
  • Handoff to the existing Change Handle dialog and a support link

The invalid handle pill on one's own profile header is now tappable to
reopen the dialog on demand, bypassing the snooze.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01LSXAgZis8iP5KmcUcGXCKw

When the signed-in account's handle comes back as handle.invalid, auto-open
a dialog (snoozed per account for 24h) that explains the problem and offers
a path to fix it:

- Refresh button: asks the server to re-resolve identity via
  com.atproto.identity.refreshIdentity, then re-syncs the session
- Server-resolution diagnostics: recovers the intended handle from the DID
  document (describeRepo alsoKnownAs) and resolves it to distinguish
  "resolves correctly now", "wrong DID", "not resolving", and
  service-provided handle issues
- Static FAQ of likely causes (missing/multiple TXT records, wrong DID,
  expired domain, propagation delay, well-known file)
- Handoff to the existing Change Handle dialog and a support link

The invalid handle pill on one's own profile header is now tappable to
reopen the dialog on demand, bypassing the snooze.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSXAgZis8iP5KmcUcGXCKw
@claude

claude Bot commented Jul 3, 2026

Copy link
Copy Markdown

Claude finished @mozzius's task in 6m 16s —— View job


Review: Add invalid handle recovery dialog

  • Read review guidance & CLAUDE.md conventions
  • Review the changed files
  • Post review feedback

Nicely structured feature — the pure diagnostics.ts / pickDiagnosis split with unit coverage is the right call, each diagnostics step is individually error-handled so the query can't throw, and the dialog inner only mounts when the sheet is open (native BottomSheet returns null while closed; web gates on isOpen), so there's no diagnostics cost for the vast majority of users who never hit this. I checked cross-platform mounting, the snooze/storage path, the refresh→resumeSession session sync, and i18n coverage.

One real bug and a couple of minor notes.


1. Switching accounts snoozes the wrong account (non-blocking, but user-visible)

src/features/invalidHandle/InvalidHandleDialog.tsx:62-68 closes the dialog on account switch, and Dialog.Outer's onClose (:74-76) treats any close as a dismissal and snoozes did:

onClose={() => {
  if (did) snooze(did)
}}

Both did and the inline onClose closure come from the same render scope, so by the time the account-switch effect fires control.close(), did has already advanced to the newly-switched-to account. onClose then runs snooze(newDid).

Scenario: user has two custom-domain accounts, both currently handle.invalid. Account A's dialog auto-opens → they switch to Account B → the effect closes the dialog and snoozes B. On web the auto-open effect (:50-56) even runs first, so B's dialog flashes open and is immediately closed + snoozed. Net result: B's recovery dialog is suppressed for 24h even though the user never saw or dismissed it — defeating the feature for exactly the multi-invalid-handle case.

The programmatic close-on-switch shouldn't count as a dismissal. One option is to distinguish it from a real dismissal (e.g. close without triggering the snooze, or guard onClose so it only snoozes the account that was actually being shown). Fix this →


2. variant="ghost" is deprecated (non-blocking, nit)

InvalidHandleDialog.tsx:234 uses variant="ghost" on the Contact-support button. Per CLAUDE.md / the Button docs, ghost is deprecated in favor of the color prop. Since this is new code, worth using the current API (color="secondary" with the appropriate ghost styling) to avoid re-introducing the deprecated pattern.


3. Dangling doc reference (nit)

types.ts:2-4 says "See README.md and diagnostics.ts" but there's no README.md in src/features/invalidHandle/. Either drop the reference or add the README (the CLAUDE.md feature-directory convention would welcome one here).


Everything else checks out: the ⚠Invalid Handle pill preserves the prior string (no new emoji-prop regression vs. the existing <Text>), strings are wrapped via Trans/l, the dev-mode debug dump is correctly gated behind devMode, and refresh's agent.resumeSession(...) correctly flows through persistSession → onSessionChange to update currentAccount.handle.
claude/invalid-handle-debug-menu-606t9b

@mozzius mozzius marked this pull request as draft July 3, 2026 21:44
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor
Old size New size Diff
8.51 MB 8.53 MB 22 KB (0.25%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants