Repository navigation
Fix Members dates, name unnamed members, paste keys in channel add - #142
Merged
Merged
Conversation
Settings > Members showed every member as added today. Each row took the created_at of the kind:13534 snapshot, one replaceable event that moves on every roster change. Read dates from the relay's kind:8000 announcements instead, in their own query since live snapshots overwrite the roster cache. A member never announced shows no date. Show a short npub instead of "Unnamed member", so two can be told apart. Let the channel add box take a pasted npub or hex key, so someone with no profile can be added. The relay checks channel policy only, so a key with no profile that isn't on the community roster gets an explanation rather than an Add row: it would seat a typo or event id as a ghost member. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 9, 2026
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.
Factory-Task: desktop/members-dates-unnamed-paste
Built-by: claude-code/claude-opus-5-5
Undo: revert this PR's merge. It changes only the desktop front end and the test mock. Nothing is stored, so there is nothing to clean up.
Three problems Russell found on 5 Nov 2026.
1. Every member showed "Added Nov 5, 2026"
Cause:
relayMembersFromEventstamped each member with thecreated_atof the kind:13534 membership snapshot. That's one replaceable event, re-signed on every roster change, so the date moved for everyone whenever anyone joined.Fix: dates now come from the relay's kind:8000 "member added" announcements, one per add. Clients can't publish that kind, because
required_scope_for_kindrejects it. If someone was removed and re-added, the newest announcement wins. A member with no announcement (the bootstrap owner, an allowlist backfill) shows no date instead of a wrong one.createdAtis gone fromRelayMember, so nothing can read the wrong date by accident.relayMemberscache withsetQueryData, which would have wiped dates merged into it.useLiveDirectoryUpdatesrefreshes the dates inside its existing 2 s window. That's at most one extra REQ per window, and only while the Members panel is open.invalidateRelayQueriescovers reconnects.Limit: it reads one page, the relay's maximum of 1,000 adds. A full page logs a console warning, and the oldest members then show no date. There's a
ponytail:comment with the upgrade path. Today's roster is 6 members with 7 announced keys.No relay change: the community is on Block's hosted relay, which the fork can't deploy to.
relay_members.created_atholds the true date, but no API exposes it and the snapshot doesn't carry it.2. "Unnamed member"
A member with no profile now shows a short npub, such as
npub1a2d…yp60, so two of them can be told apart without hovering. The "Actions for…" labels are distinct too, and the remove dialog already showed the full key. The owner keeps "Community owner", since there's only one.No local label: the app has no local-name store or surface. NIP-02
petnameexists in thesocial.tstypes, but nothing displays it. A label would need its own store and UI on every surface that shows a name, and the short npub already solves telling people apart. Add one if Russell wants names for people who never set a profile.3. Pasting a key in "Add people and agents"
It didn't work: the sidebar only ran user search, which matches profile text and never keys. So someone with no profile couldn't be added from there. Now a pasted npub or hex key (any case, surrounding whitespace is fine) searches as its hex form:
A difference from
ChannelMemberInviteCard: the relay checks channel policy only, so it would seat any 64-hex string: a typo, an event id, or someone who can't get into the community. That leaves a ghost member. The sidebar checks the roster first, and the invite card still doesn't. I left the card alone to keep this PR small.Enter after a paste: Enter now uses the existing
getKeyboardSearchSelection, so it can't add the previous search's top row before the new results render.How it was checked
Against Block's live relay (dev build, launch-check member, read-only through a temporary log line that isn't in this diff):
created_atwas2026-11-05T15:52:34Z, the date Russell saw on every row.Tests: Unit 7,205 + 193 jsdom pass.
tsc, biome, file-size and pubkey-truncation checks are clean. Playwright on the 15 specs that touch the sidebar or roster: 396 of 400 pass locally. The other 4 are unrelated to this change:community-rail:822andonboarding:2909fail 3 of 3 here and on clean main too;community-rail:1474passed 3 of 3 on rerun;channels:5580is a page-boot timeout under machine load that passed 10 of 10 on both builds.Each behavior was undone to confirm its test fails: date source, short npub, paste row, npub matching current members, profile lookup, roster gate, empty-roster guard, live refresh. The malformed-key test passes either way, as a negative guard should.
Agent review: an independent review found six issues, and all are fixed here: the refresh depended on desktop notifications, the key was missing from reconnect recovery, ghost members, one REQ per person on a multi-select add, Enter on stale results, and a failed lookup offering an agent as a person.
Not checked in the real app: the rendered Members list and sidebar against the live relay. The app-control grant was declined, and the launch-check member isn't an owner or admin, so it can't open Members normally. Both were checked rendered in Playwright against the mock. No real member was added, since that writes to the live community. Not covered by a test: the failed-lookup message, which only appears after about 7 s of retries. The first real look is Russell's own Settings > Members, and a paste in a channel's add box.
Needs a launch check when its train asks, since it touches
desktop/.🤖 Generated with Claude Code