Skip to content

fix(desktop): enrich relay agent directory for @mention eligibility (#5363) - #5483

Open
rmichelena wants to merge 18 commits into
block:mainfrom
rmichelena:fix/desktop-mention-relay-agents-5363
Open

fix(desktop): enrich relay agent directory for @mention eligibility (#5363)#5483
rmichelena wants to merge 18 commits into
block:mainfrom
rmichelena:fix/desktop-mention-relay-agents-5363

Conversation

@rmichelena

@rmichelena rmichelena commented Aug 10, 2026

Copy link
Copy Markdown

Fixes #5363.

Root cause: the data never reaches the eligibility layer

list_relay_agents (desktop/src-tauri/src/commands/agent_discovery.rs) builds the relay-agent directory from kind:10100 only. But an agent's respond_to policy is published as kind:30177 (KIND_MANAGED_AGENT, d-tag = agent pubkey) and its channel membership as kind:39002 (NIP-29 members list, one event per channel).

agents_from_events does parse respond_to / channel_ids when they happen to be embedded in the 10100 content — but agents that publish policy and membership in the dedicated 30177 / 39002 events arrive with respond_to: null and channel_ids: [].

Downstream, relayAgentCanRespondInChannel then returns false and shouldHideAgentFromMentions hides the agent — even for a channel member, and even for the agent's own owner. Owner-affected reproduces, which rules out the authorization branch as the sole cause.

This is why the symptom survives #4913: that fix (and the other open attempts) corrects the eligibility computation, but the directory feeding it is missing the policy and membership data in the first place.

Change

Rust (core fix) — new desktop/src-tauri/src/commands/agent_discovery/relay_enrich.rs:

  • Enriches the kind:10100 directory by merging kind:30177 (policy, batched query) and kind:39002 (#pchannel_ids).
  • kind:30177 is scoped by verified owners (kind:0 lookup) so a third party cannot spoof another agent's policy; unparsable or d-tag-less events are skipped with a tracing::warn!.
  • Best-effort: a relay error during enrichment degrades to 10100-only rather than emptying autocomplete.
  • Batch query limits are sized by event cardinality (39002 is one event per channel, not per agent).
  • Unit tests for the merge/dedup helpers included.

Rationale for merging rather than requiring a fatter kind:10100: 39002 is the relay-authoritative NIP-29 membership (stronger than a self-reported channel_ids) and 30177 is the live policy event, so both are better sources than a snapshot baked into the profile.

TS (optional hardening, separate commits)useComposerMentionableAgentPubkeys.ts, extracted out of useMentions.ts:

  • Channel-membership fallback for the 39002 propagation window.
  • Kept fail-closed: only admits respond_to: "anyone"; owner-only / allowlist agents stay hidden (covered by a test).
  • Happy to drop these commits if maintainers prefer a Rust-only change.

Diffstat: 6 files, +812 / −46 (the bulk is the new relay_enrich.rs module and its tests).

Verification

  • End-to-end on a self-hosted relay (wss://buzz.infinitek.pe, stream channel 273e2bad): before — remote/VPS-hosted agents absent from the @ list; after — all relay agents (including two VPS-hosted ones with respond_to: anyone) appear and mention delivery works. Confirmed by a human operator from a locally-built desktop client, with the mentioned agents receiving and replying to the events.
  • pnpm --dir desktop check → exit 0
  • pnpm --dir desktop typecheck → exit 0
  • pnpm --dir desktop test → 4540 passed / 0 failed
  • just desktop-tauri-fmt-check / desktop-tauri-clippy (-D warnings, --workspace --all-targets) / desktop-tauri-test → exit 0; 2282 passed / 0 failed in the main crate, including the 12 relay_enrich::tests (owner-verification, 30177 merge/dedup, 39002 #p grouping, query-limit sizing)
  • desktop/scripts/check-file-sizes.mjs ratchet respected (that's why the Rust enrichment lives in its own module and the TS hook was extracted out of useMentions.ts).

Supersedes

Same symptom, eligibility-layer-only: #3292, #5084, #4603, #4517, #2693, #4047, #4137, #4546. #4546 touches the Rust types but not the directory query. Those patches are compatible with this one but are not sufficient on their own, because the respond_to / channel_ids they branch on are still null / [].

rmichelena and others added 18 commits August 10, 2026 12:02
…lock#5363)

Merge kind:30177 respond_to policy and kind:39002 channel membership into
list_relay_agents so block#4913 mention gates see production data (kind:10100
profiles are sparse). Add channel-member bot fallback in useMentions when
directory channel_ids lag behind live membership.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Degrade gracefully when kind:30177 batch or per-agent kind:39002
membership queries fail instead of emptying the whole autocomplete.
Extract pure helpers for testability and add unit tests for d-tag
parsing, 30177 indexing, and channel_id merge/dedup.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Avoids clippy unused_mut warning that fails CI with -D warnings.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Rust: batch kind:30177/39002 queries with #d/#p filters and explicit
limits; NIP-OA owner filter + created_at tie-break for 30177; batch
membership grouping. TS: fix crashing test fixture (missing pubkey),
add allowlist+lag-window test, document community-scope omission.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
39002 returns one event per channel, not per agent — size limit from
union of kind:10100 channel hints with headroom. 30177 allows multiple
events per d-tag (multi-author) with 4× agent headroom above relay default.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Fail-closed kind:30177 when NIP-OA owner is unverified, fix query-limit
test assertions against the relay floor, remove dead membership helper,
parallelize kind:0/39002 fetches, and add community-scope plus channel-switch
hardening tests.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
…lock#2)

Add server-side authors filter from NIP-OA owner map and skip the
30177 fetch when no owners are verified. Fix misleading kind:0 error
log to reflect fail-closed enrichment behavior.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Owner-verified kind:30177 now overrides 10100 respond_to; sparse 39002
queries request up to relay max page limit; successful membership query
replaces channel_ids instead of unioning with stale 10100 hints.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Remove dead merge_channel_ids helper, preserve 10100 channel hints when
39002 page omits an agent, tie-break kind:30177 by event id on equal
created_at, and document community-scope SECURITY trust boundary.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Unblocks desktop-tauri-fmt-check on Mac after L2 tie-break formatting.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Use event.tags.iter(), block-scoped match insert arm, and
EventBuilder::custom_created_at in L2 tie-break test.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Unblocks desktop-tauri-clippy on Mac with -D warnings.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Unblocks pnpm check on Mac after L5 SECURITY comment edits.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Move kind:30177/39002 enrichment into agent_discovery/relay_enrich.rs and
resolve channel-member hints via AgentEligibilityScope so useMentions.ts
stays within its grandfathered line cap.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
…entions.

Move scope construction to getMentionableAgentPubkeysFromComposer and a
small hook so useMentions.ts stays within the file-size ratchet.

Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
@rmichelena
rmichelena force-pushed the fix/desktop-mention-relay-agents-5363 branch from dc159f3 to b241573 Compare August 10, 2026 20:01
@rmichelena
rmichelena force-pushed the fix/desktop-mention-relay-agents-5363 branch from b241573 to 3eaadbb Compare August 10, 2026 20:03
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.

Relay-discovered agent with respond_to=anyone still never appears in @-mention autocomplete (regression/incomplete case of #4913)

1 participant