Skip to content

Editing a community's Relay URL orphans the existing Welcome Team and mints a fresh Fizz/Honey/Bumble trio (exact-string match, no canonicalization) #5109

Description

@jcg-git

Summary

Changing a community's configured Relay URL to a different string — even when it points at the exact same relay — silently orphans the existing Welcome Team (Fizz/Honey/Bumble) and mints a brand-new trio with fresh keypairs. This is a distinct root cause from #2648 (second Desktop install) and #3639 (forceNewInstance: true on "Deploy team to channel"): no second install and no manual team-deploy involved, just an ordinary relay URL edit.

Root cause

Two places do a bare exact-string comparison on the relay URL, with no canonicalization anywhere in the path:

  1. hasEnsuredWelcomeChannel / markWelcomeChannelEnsured (desktop/src/features/onboarding/welcome.ts:284-324) build a localStorage key by embedding communityScope (= activeCommunity.relayUrl, unmodified) verbatim via welcomeChannelEnsuredStorageKey. A different string for the same relay → cache miss → treated as a never-provisioned community.
  2. isAgentScopedToRelay (desktop/src/features/onboarding/welcomeGuide.ts:56-62), used by pickWelcomeTeamStarterAgentForRelay, compares normalizeRelayUrl(agent.relayUrl) === normalizeRelayUrl(targetRelayUrl)normalizeRelayUrl only trims trailing slashes, it doesn't resolve hostnames vs IPs vs schemes to a canonical identity. An existing Fizz/Honey/Bumble stamped with one string is invisible to a lookup using a different (but logically identical) string.

The re-provisioning path itself is useAppOnboardingState's effect in desktop/src/features/onboarding/hooks.ts:578-595, which calls requestStarterChannels(false)initializeStarterChannelsseedWelcomeExperienceensureWelcomeTeam (welcomeGuide.ts:343-356provisionWelcomeTeam) whenever hasEnsuredWelcomeChannel misses for the current communityScope. provisionWelcomeTeam (welcomeGuide.ts:268-341) does look for an existing agent per persona via pickWelcomeTeamStarterAgentForRelay before creating one — but since that lookup is also keyed on the (mismatched) relay URL string, it never finds the existing instance and calls createManagedAgent instead, minting a new keypair.

Real-world reproduction (not a synthetic repro — this is what actually happened on one Desktop install)

Self-hosted single-user community, single Desktop install, no second machine, no manual "Deploy team to channel" click. managed-agents.json currently has 3 records each for Bumble/Fizz/Honey (9 total for what should be 3), in three timestamp clusters, each stamped with a different relay_url:

relay_url on the created agents Created at Trigger
ws://localhost:3000 2026-07-22T19:28 First-run default (defaultRelayUrl in useCommunityInit.ts), before the real relay was configured
ws://100.119.50.98:3000 (a raw Tailscale IP, non-TLS, port 3000) 2026-07-27T21:33 Community's Relay URL edited to point at the relay via its Tailscale IP directly
wss://<tailscale-magicdns-hostname>:8443 (the final, correct address, TLS-terminated via tailscale serve) 2026-07-27T21:39 (six minutes later) Community's Relay URL edited again, to the final hostname, while wiring up mobile pairing that same session

Every persona has a distinct pubkey per cluster. The two abandoned clusters are stale: never restarted since creation (last_started_at: null), sitting as dead bot members in the private "Welcome" channel with the same display names as the live ones, indistinguishable in the @mention picker (same failure mode independently reported in #2648 by AI-OWEN).

The user reported having removed the stale channel members once already; they reappeared "a few minutes later" — which lines up exactly with the two edits six minutes apart above, not a background process re-triggering on every app launch. Desktop has since run 13+ continuous hours without the relay URL changing again, and no further duplicate cluster has appeared, consistent with the trigger being the URL edit itself rather than a boot-time race.

Expected behavior

Editing a community's Relay URL should not orphan and re-mint the Welcome Team. Options:

  • Resolve/canonicalize relay identity by community ID (already the real join key elsewhere in the app) rather than the raw URL string, for both the localStorage ensured-marker and the agent-reuse lookup.
  • At minimum, when a Relay URL is edited for an existing community, offer to re-point (not re-mint) the existing Welcome Team agents at the new URL, the same way other community-scoped state gets migrated on a relay change.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions