fix(desktop): centralize known-agent trust set in useKnownAgentPubkeys#1703
Draft
matt2e wants to merge 2 commits into
Draft
fix(desktop): centralize known-agent trust set in useKnownAgentPubkeys#1703matt2e wants to merge 2 commits into
matt2e wants to merge 2 commits into
Conversation
The config-nudge trust gate (and bot avatars/popovers/mention pills) previously depended on per-surface agent-pubkey sets derived from different sources: the channel screen merged channel members + managed agents + relay agents + profile isAgent flags, the Home inbox derived its set from feed agent activity + profiles, and several surfaces passed nothing at all. The same event could therefore render the ConfigNudgeCard on one screen and fail the gate on another. Centralize the baseline in a new workspace-scoped useKnownAgentPubkeys hook (managed agents ∪ relay agents ∪ home-feed agent activity, backed by React Query so it follows workspace switches without a resetWorkspaceState entry, content-stabilized via a new useStableSet helper). MessageRow now consumes the hook directly — the agentPubkeys prop and its drilling through ChannelPane, MessageTimeline, TimelineMessageList, and MessageThreadPanel are removed — and folds in the signer profile's isAgent flag with per-pubkey O(1) checks instead of the old per-surface set scans. getConfigNudgeAuthorPubkey takes the predicate instead of a set. ChannelScreen and HomeView keep their surface-local extras (channel-member roles, profile-lookup scans) for non-MessageRow consumers, but union them on top of the shared baseline so they can only widen trust, never diverge from it. Implements step 2 of the config-nudge rendering plan; step 1 (graceful prose fallback when the gate fails) is separate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Follow-up to the useKnownAgentPubkeys centralization (1911921), whose review flagged that subscribing the three source queries inside every MessageRow caused refetch churn (each batch of row mounts re-triggered stale-data refetches, including the deliberately relaxed unfiltered listRelayAgents query) and periodic full-timeline render sweeps (source polls re-rendered every mounted row before useStableSet could bail), and that agents known only through channel membership (role "bot" or member isAgent, with no profile flag and no managed/relay/feed presence) regressed from bot to human rendering in rows. Restructure useKnownAgentPubkeys as a KnownAgentPubkeysProvider that owns the app's only subscription to the source queries and publishes the content-stable merged set over context; the hook keeps its name and call sites and now just reads the context (empty set outside the provider). The provider mounts in AppReady around RouterProvider, under the workspace-keyed WorkspaceQueryProvider remount boundary, so observers tear down on workspace switch without a resetWorkspaceState entry. Query churn re-renders only the provider — children are referentially stable — and consumers re-render only on actual membership change. Restore member-only bot trust by folding channel-member agent flags into the profiles lookup MessageRow already receives and memo-compares: a new mergeMemberAgentFlagsIntoProfiles (sibling to mergeAgentNamesIntoProfiles) marks bot-role/isAgent members as isAgent: true, so MessageRow's per-pubkey profiles[pk]?.isAgent check — the config-nudge gate, agent mention pills, popover role — sees them again. The merge + profileLookupsEqual ref stabilisation moved from ChannelScreen into a new useMessageProfiles hook, ratcheting the ChannelScreen file-size override 1002 -> 972. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
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.
Summary
Different desktop surfaces (channel timeline, thread panel, home inbox) each derived their own "known agent pubkeys" set from different source subsets, so the same event could pass the agent trust gate on one screen and fail it on another. This PR centralizes that baseline in a single shared hook.
useKnownAgentPubkeyshook (desktop/src/features/agents/useKnownAgentPubkeys.ts): the workspace-scoped known-agent baseline — managed agents ∪ relay-registered agents ∪ home-feed agent activity, normalized vianormalizePubkey. Backed by React Query (follows workspace switches for free) and content-stabilized via a newuseStableSethelper so the set is safe as a memo dependency in render-hot consumers.mergeKnownAgentPubkeys(knownAgentPubkeys.ts) with node unit tests covering source merging, undefined sources, and case/whitespace normalization.MessageRowderives agent-ness itself from the shared baseline plus a per-pubkeyprofiles[pk]?.isAgentcheck, instead of receiving anagentPubkeysprop. The prop is removed from the entire pass-through chain (ChannelPane→MessageTimeline→TimelineMessageList→MessageRow, andMessageThreadPanel), shrinking theReact.memocomparator surface.getConfigNudgeAuthorPubkey(the config-nudge trust gate) now takes anisKnownAgentPubkeypredicate instead of a raw set, so surface-local signals compose with the shared baseline; signer-vs-attributed-author semantics are unchanged and tests are updated.ChannelScreenandHomeViewnow widen the shared baseline with their surface-local signals (channel-member roles, profile lookups) rather than building independent sets.Surface-local signals remain additive on top of the baseline — they can widen it but never diverge from it.
Testing
mergeKnownAgentPubkeys(merge, empty, normalization/dedup)configNudgeAuthPubkeytests for the predicate signature🤖 Generated with Claude Code