Skip to content

feat(linked-accounts): surface unverifiable claims behind opt-in toggle#413

Open
jalcine wants to merge 3 commits into
mainfrom
feat/linked-accounts-show-unverified
Open

feat(linked-accounts): surface unverifiable claims behind opt-in toggle#413
jalcine wants to merge 3 commits into
mainfrom
feat/linked-accounts-show-unverified

Conversation

@jalcine

@jalcine jalcine commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a user-controlled "Show unverified" toggle to LinkedAccounts that reveals NIP-39 external identity claims the verification service cannot auto-verify, behind a Question icon and a "Verify manually" link in the popover.
  • Verified path is unchanged: green check, full popover.
  • Cache error: 'manual' results so badges appear immediately on subsequent page loads instead of flickering through a loading state.
  • Stop discarding the manual cache entry in IdentityBadge so the cached result is now used as initialData.

Note: PR body avoids naming specific Bluesky PDS-viewer domains. The reported user-facing symptom is documented in #412.

Motivation

When a kind:10011 external identity claim cannot be auto-verified by the verification service — for example, a Bluesky account linked via a proof post on a non-canonical PDS-viewer, or any other platform where the service returns error: 'manual' — the linked-account badge is currently hidden entirely from the profile.

This means legitimately-linked accounts are invisible: the kind:10011 event is published (the user gets a "Linked" toast), but the badge never appears on the profile.

This PR adds a small opt-in toggle so users can reveal these claims explicitly. The verified path is unaffected, and the toggle state persists in localStorage.

Related Issue

Testing

  • npm run test (type-check, lint, 1126 unit tests, build) passes locally on feat/linked-accounts-show-unverified
  • npx vitest run src/components/LinkedAccounts.test.tsx passes (7 tests, all new behavior covered)
  • npx vitest run src/hooks/useExternalIdentities.test.ts passes (49 tests, cache change is non-breaking)
  • npx vitest run src/lib/i18n/locales.test.ts passes (locale parity maintained across 16 locales)
  • Manual verification on dev server — recommend verifying:
    1. Profile with a verified claim still shows the green check
    2. Profile with an unverified claim shows nothing by default
    3. Toggling "Show unverified" reveals an amber ? badge
    4. Clicking the badge shows the "Verify manually" link in the popover
    5. Reloading preserves the toggle state

Visuals

  • UI change with screenshots/video attached — maintainer to capture before merge (toggle introduces a new button and a new badge variant)
  • No visual change for the verified path (green check + existing popover)
  • Visuals and text avoid sensitive external brand or partner names (no Bluesky PDS-viewer domains named)

Diff summary

  • src/components/LinkedAccounts.tsx — three-tier render (verified / manual / error), Show unverified toggle button, buildManualVerifyUrl helper
  • src/components/LinkedAccounts.test.tsx — 6 new tests covering the new behavior + 1 updated existing test
  • src/hooks/useExternalIdentities.ts — cache error: 'manual' results so the toggle UX is stable across page loads
  • src/lib/i18n/locales/{ar,de,en,es,fil,fr,id,it,ja,ko,nl,pl,pt,ro,sv,tr}/common.json — 7 new keys + 1 updated key (English source; other locales inherit English until translated)

Blocked by

This PR is blocked by divinevideo/divine-identify-verification-service#12 (the service-side fix that switches the verification AppView to public.api.bsky.app). Merging this client PR first is fine — the toggle is defense-in-depth and remains useful after the blocker merges.

When a kind:10011 external identity claim cannot be auto-verified by the
verification service (e.g. for Bluesky accounts on a non-canonical PDS-viewer,
or when the service returns a 'manual' result), the LinkedAccounts component
currently hides the badge entirely. This makes legitimately-linked accounts
invisible on profiles.

Add a user-controlled 'Show unverified' toggle that reveals these claims
behind a Question icon and a 'Verify manually' link in the popover. The
verified path is unchanged. Toggle state persists in localStorage.

Also cache 'manual' verification results so the badge appears immediately
on subsequent page loads instead of flickering through a loading state.
Stops discarding the 'manual' cache entry that was previously used as
initialData in IdentityBadge.

Closes #412.

Refs divinevideo/divine-identify-verification-service#12 (blocker: the
underlying verification service still hardcodes bsky.social and fails to
auto-verify these claims; the upstream PR switches the service to
public.api.bsky.app).
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

🚀 Preview Deployment

Property Value
Preview URL https://d0a2dc71.divine-web-fm8.pages.dev
Commit 224f693
Branch feat/linked-accounts-show-unverified

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 18, 2026

Copy link
Copy Markdown

Deploying divine-web with  Cloudflare Pages  Cloudflare Pages

Latest commit: 224f693
Status: ✅  Deploy successful!
Preview URL: https://3228f027.divine-web.pages.dev
Branch Preview URL: https://feat-linked-accounts-show-un.divine-web.pages.dev

View logs

…1 read path

Add LinkedAccountsDebug component that renders below LinkedAccounts and
the settings page identity list. Gated on the ?debug query param so it
ships invisibly to real users. Surfaces the raw useExternalIdentities
query state (status, fetchStatus, error, identities, queryKey) to
diagnose why unverified kind:10011 claims render nothing on the
profile page.

This is a temporary diagnostic. Remove before merging #413 once the
issue is diagnosed and fixed.
The diagnostic render (gated on ?debug=linked-accounts) served its
purpose: confirmed useExternalIdentities is stuck in 'fetching' state
when wss://relay.ditto.pub/ is unreachable from the browser. The query
never resolves because NPool waits for all configured relays to
respond. The relay routing bug is tracked separately in #415.

The verifyer-service 401 is tracked in the comment on
divinevideo/divine-identify-verification-service#12.

Keep the 'Show unverified' toggle and the manual cache write from #413
intact; the toggle remains useful as defense-in-depth once #415 and
#12 (or its successor) are resolved.

Closes #412.

@rabble rabble left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for missing visual evidence. This PR adds visible profile UI: the opt-in toggle at src/components/LinkedAccounts.tsx:276-288, the unverified badge variant at src/components/LinkedAccounts.tsx:126-134, and new popover states at src/components/LinkedAccounts.tsx:159-189. The PR body still leaves UI screenshots/video unchecked and manual visual verification unchecked. Repo rules require visual evidence for UI changes, so please attach toggle-off, toggle-on, and popover screenshots/video before merge.

I did not find a code-blocking issue in the linked-account logic. Minor follow-up: non-English locale files currently get English strings, e.g. src/lib/i18n/locales/de/common.json:675-681.

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.

Linked Bluesky account on non-bsky.app viewer doesn't show on profile

2 participants