fix(desktop): make cross-owner channel-member agents mentionable - #4716
fix(desktop): make cross-owner channel-member agents mentionable#4716oleg-ai-dev wants to merge 1 commit into
Conversation
|
@oleg-ai-dev @dexsynccom @anindyar, after comparing all three patches, I think each contributes part of the best fix. #4714 keeps the mention change narrow. #4716 correctly identifies the instance-tier policy and adds the cross-identity E2E proof this bug needs. #4713 recognizes that runtime discovery should be signed by the agent itself. I would preserve all three contributions. I still don’t think #4716’s My preferred combination is #4714’s mention fix, #4716’s policy handling and E2E coverage, and an agent-signed
If the |
|
Opened #5483 on the same layer, so this is a note from the one other PR that touches One factual correction on the premise for repointing, because it changes what the fix should be:
True of Desktop's own code, but not of deployments. Headless So repointing
The second row is the bug both of us set out to fix; the first row is the population #2987 is about. A headless agent has no Desktop, so nothing publishes a I've changed #5483 to read the union of both kinds, keyed by agent pubkey, then enrich with Not asking you to close this — the union is a small change on top of what you already have, and if you'd rather carry it here I'm happy to close mine instead. The part I'd push back on either way is dropping |
…ests main's frontend mention gate (block#4913, block#6338) and backend list_relay_agents sourcing already fix the original bug this branch targeted, so those changes are dropped as superseded during this rebase. block#6338 added coverage for the owner-only-build variant, but the default-build path for a cross-owner relay agent with respond_to=anyone was still untested. Decouple the default relay-agent-directory fixture (alice/charlie) from the real human TEST_IDENTITIES pubkeys they coincidentally reused, extend the relay-agent mock seed to also register real channel bot membership, and add tests mirroring the exact reported repro: a bot member of a shared channel, owned by another identity, with respond_to=anyone, must be mentionable — and must stay hidden if it is only relay-directory-listed without real channel membership. Signed-off-by: oleg-ai-dev <oleg.ai.development@gmail.com>
4a0c092 to
16ff686
Compare
|
Rebased this onto current Going through the conflicts, I found that the frontend gate fix (commit 1) and the backend
Both of those commits became empty diffs once rebased onto CI status locally: Given |
Problem
A bot agent that is a member of a channel shared between two different Buzz identities can never be
@-mentioned (or manually addressed via a typed mention) by anyone except the human who owns/hosts it — even when the agent'srespond_toisanyone. Reported and reproduced independently across desktop v0.4.20–v0.5.3, macOS/Windows, hosted/self-hosted relays: #3776 (canonical, most precise), #3277 (original report + a documented client-side stopgap), #2349 (long thread with the business case for team use), #2950.Heads up to reviewers: I'm aware this issue already has a large number of open PRs attempting the same fix. I looked through the ones I could find before opening this — none of the ones I checked source
respond_to/respond_to_allowlistfrom the correct (instance-tier) fields (see Cause 2 below), which as far as I can tell would leave the exact same bug at a different codepath if merged as-is. Flagging that here explicitly in case it's useful for triage, independent of whether this particular PR is the one that ends up merged.Root cause (two independent, stacked causes — both are required to fix this)
Cause 1 — the mention picker drops any agent you don't personally manage.
isAgentIdentityInManagedList(inagentAutocompleteEligibility.ts) only admits a candidate if it isn't flagged as an agent, or if its pubkey is in the viewer's ownmanagedAgentPubkeys— built solely from the locallist_managed_agentsTauri command. An agent owned by the other identity never enters that set (by design — managed-agent records hold device-local secrets and are never minted from a relay event). So the other person's agent is dropped inuseMentions.tsbeforeshouldHideAgentFromMentions/relayAgentIsSharedWithUserever run — including for a manually typed mention, sinceextractMentionPubkeysonly resolvesptags from the already-filtered candidate list.Cause 2 — the eligibility check reads an event kind nothing publishes. Even with Cause 1 fixed,
relayAgentIsSharedWithUserreadschannelIds/respondTo/respondToAllowlistfrom aRelayAgentsourced fromlist_relay_agents(agent_discovery.rs), which queries the relay forkind:10100. Nothing in the codebase publisheskind:10100as an agent profile (the only writer isbuzz channels set-add-policy, which writes unrelatedchannel_add_policycontent). Agent identity/config is actually published askind:0+kind:30177(managed_agents/agent_events.rs), which the eligibility code never reads — so theRelayAgentit needs is always empty, andrelayAgentIsSharedWithUseralways returnsfalse.Note: the agent-side authorization logic is already correct and needed no change —
author_allowedinbuzz-acpalready permits any author forRespondTo::Anyoneoutside DMs. The agent would answer if it could be addressed; it just could never produce a mention.Fix
mentionableAgentPubkeysset (which already accounts for relay-directory sharing) into theisAgentIdentityInManagedListgate, so a real channel member is admitted when it's shared, while relay-directory-only (non-member) agents stay hidden exactly as before. Same relaxation applied toextractMentionPubkeysso a p-tag is actually emitted for a manually typed mention of such an agent.list_relay_agents(agent_discovery.rs) fromkind:10100tokind:30177, and resolve channel membership via akind:39002 #pquery — the same patternbuzz-acp's own channel-discovery code already uses. The agent's pubkey is read fromkind:30177'sdtag (not the event's own pubkey, sincekind:30177is a parameterized-replaceable event published by the owner).respond_to/respond_to_allowlistare sourced from the record's instance-tier runtime fields, not the definition-tier fields — the snapshot this event is built from carries both, and they can diverge in practice (the running harness is spawned from instance-tier fields). Sourcing from definition-tier would ship a policy the running agent doesn't actually enforce (agent visible but silent, or answering but hidden).Test plan
agentAutocompleteEligibility.test.mjsfor the new gate logic, including the two cases that must stay hidden: a non-member agent that's only relay-directory-listed, and a channel member with an explicit not-invocable directory entry.mentions.spec.tsmirroring the exact reported repro: identity A creates an agent withrespond_to: anyone, adds it as a bot member of a channel shared with identity B; identity B can now see and use the mention, and a non-member/non-invocable agent stays hidden.cargo fmt --all -- --checkandcargo fmt(Tauri crate) clean.cargo clippy --all-features -- -D warningsreports zero issues in either file this PR touches (agent_discovery.rs,nostr_convert.rs). Note: the same command surfaces ~30 pre-existing warnings/errors in unrelated files on a cleanorigin/maincheckout under Windows +--all-features(confirmed by checking out main and re-running) — those are not introduced by this change and are left untouched per the "no drive-by fixes" guidance inCONTRIBUTING.md.tsc --noEmitclean.biome checkclean on all changed files.Closes #3776. Related: #3277, #2349, #2950.