Repository navigation
Description
Summary
The mention picker admits the owner of an owner-only relay agent, but it does not admit the owner of an allowlist relay agent. The harness admits the owner in both modes. So widening an agent's policy from owner-only to allowlist removes that agent from its own owner's autocomplete.
Both branches live in the same function, eight lines apart.
The two sides
Harness — crates/buzz-acp/src/lib.rs:249-257. The owner is accepted in both modes; Allowlist only adds the external pubkey list on top:
match respond_to {
RespondTo::Anyone => true,
RespondTo::Nobody => false,
RespondTo::OwnerOnly => is_owner_or_sibling(author, owner_cache, rest_client).await,
RespondTo::Allowlist => {
allowlist.contains(author)
|| is_owner_or_sibling(author, owner_cache, rest_client).await
}
}The doc comment on the same function (lib.rs:218-222) states it as the intended rule, not as an accident:
Both
OwnerOnlyandAllowlistaccept the owner and same-owner siblings;Allowlistadditionally accepts the explicit external pubkey list.
Startup logging treats owner matching under allowlist as a feature that can be missing (lib.rs:2029-2034):
respond-to=allowlist but no owner is set — allowlisted pubkeys will still be accepted, but owner-based matching is unavailable until owner is resolved.
Client — desktop/src/features/agents/lib/agentAutocompleteEligibility.ts:24-36. The owner-only branch resolves the owner. The allowlist branch reads the array literally and never looks at agent.ownerPubkey:
if (
agent.respondTo === "owner-only" &&
normalizedCurrentPubkey &&
agent.ownerPubkey
) {
return normalizePubkey(agent.ownerPubkey) === normalizedCurrentPubkey;
}
if (agent.respondTo === "allowlist" && normalizedCurrentPubkey) {
return agent.respondToAllowlist
.map((pubkey) => normalizePubkey(pubkey))
.includes(normalizedCurrentPubkey);
}Two results
1. Widening the policy hides the agent. An owner who moves an agent from owner-only to allowlist, to let one more person in, loses the agent from their own picker. The agent still answers them — the harness accepts the owner — but the owner can no longer select it, and a typed mention is not tagged.
2. An empty allowlist hides the agent from everybody, including the owner. respond_to=allowlist with an empty respond_to_allowlist is accepted by the harness for the owner, and hidden by the client from all users. Nothing reports an error.
Who is affected
getMentionableAgentPubkeys seeds its set from managedAgentPubkeys unconditionally (agentAutocompleteEligibility.ts:76-78), so an agent this Desktop runs stays mentionable whatever its respond_to is. The affected population is agents the viewer owns but does not run under this Desktop: headless agents, and agents running on the owner's other machine.
Steps to reproduce
- Run an agent outside Desktop with
--respond-to allowlistand an allowlist that does not contain the owner's own pubkey.BUZZ_AUTH_TAG/--agent-owneris set, so the harness knows its owner. - Open Desktop as that owner, in a channel the agent is in.
- Type
@and look for the agent.
Expected: the agent is offered, because it answers the owner.
Actual: the agent is not offered. Setting the same agent to --respond-to owner-only makes it appear.
Test coverage
agentAutocompleteEligibility.test.mjs:104 covers the allowlist branch for a viewer in the array and for a viewer not in the array. The negative fixture has no ownerPubkey field, so the owner case is not pinned in either direction — it is uncovered rather than intended.
Not a duplicate
- Desktop hides allowlisted agents owned by another user from @mention autocomplete #3125 — the viewer is in the array and is dropped by the managed-list gate from fix(desktop): prefer live agent mentions #2149. Different mechanism, and the viewer there is not the owner.
- Managed built-in agent allowlist UI diverges from persisted runtime allowlist #3030 — the saved allowlist differs from the running one. That is persistence; this is the eligibility read of a correct record.
On a fix
The allowlist branch can accept the viewer when agent.ownerPubkey matches, mirroring the branch above it. Two limits are worth stating with it:
- Where the owner does not resolve, the branch must keep failing closed. On closed relays the NIP-OA attestation often does not materialize (NIP-OA owner attestation silently discarded on closed relays when the agent is a direct relay member #4223, relay-side fix in fix(relay): record the NIP-OA owner for direct members on closed relays #5581), and the same gap already affects
owner-only. - Sibling parity is not needed here.
is_owner_or_siblingalso accepts same-owner sibling agents, but the picker'scurrentPubkeyis the human viewer, so only the direct owner check applies.
Until the client matches the harness, putting the owner's own hex into respond_to_allowlist is the reliable configuration.
Verified on main at 93114c9c.
Activity