block / block/buzz

Inbox reply to a channel thread drops the thread's agent audience — reply is sent with no p tag, agent never addressed

Open
#7,625 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

## Summary

Replying from the Desktop **Inbox** to a channel thread can publish a kind:9 reply with **no `p` tag at all**, even though the thread root p-tags a managed agent and the reply text contains a visible `@Agent` mention. Agent harnesses address on `p` tags only (`buzz-acp` `require_mention` matches the agent pubkey in `p`), so the agent never receives the message. Re-typing the same message from the channel/thread view in the main window works immediately.

This is distinct from the neighbouring reports:

- #7044 — there the agent `p`/`mention` tags **are** present and the `h`/`e` routing identifiers are wrong. Here the routing is fine and the `p` tag is missing entirely.
- #3032 — that is the general NIP-10 "reply does not p-tag the parent author" case, for any reply builder. Here the *thread agent audience* (agents taken from the root's `p` tags) is dropped on the Inbox path specifically, while the same thread addresses correctly from the channel view.
- #5632 — DM delivery race, message disappears. Here the event persists correctly; it is simply addressed to nobody.

## Environment

- Buzz Desktop `0.5.x`, Linux
- Self-hosted relay, managed ACP agents (`buzz-acp`) in a normal channel
- Observed 2026-09-13

## Reproduction

1. In a channel, have a managed agent post in a thread whose **root event p-tags that agent**.
2. Open that thread from the **Inbox** (not from the channel view).
3. Reply with an explicit `@Agent …` mention.
4. Observe: the event is stored and rendered, but carries only `e` tags. The agent does not react.
5. Open the same thread in the channel view and send the same text: the event now carries `["p", ]` and the agent answers.

## Signed-event evidence (same channel, same thread `274d4799…`)

| Event | Origin | Tags |
|---|---|---|
| `274d4799…` (thread root) | channel view | `p: aa0066a4…` (agent) |
| `88d43e55…` reply, text contains `@Agent` | **Inbox** | `e: 274d4799… reply` — **no `p`** |
| `2f8f2a44…` reply | channel view | `e` + `p: 59082f23…` |

## Likely boundary

`desktop/src/features/home/ui/InboxDetailPane.tsx` derives the composer's audience context from the thread root's tags by *searching the already-rendered list*:

```ts
const isThreadContext = !isDirectMessage && hasInboxThreadContext(item, messages);
const threadRootTags = isThreadContext
? (displayMessages.find((message) => message.id === item.conversationId)?.tags ?? [])
: [];
```

That value is handed to `MessageComposer` as `audienceContext.rootTags` and is the only input `useThreadAgentAudience` (`desktop/src/features/messages/ui/useThreadAgentAudience.ts`) has for discovering which agents the thread addresses. Two ways it silently yields an empty audience:

1. The root event is **not in `displayMessages`** — the Inbox pane loads a windowed context and the root may not be hydrated (see #4498 for the related cold-start context gap). `?? []` turns the miss into "this thread addresses no agents" instead of an error or a fetch.
2. `hasInboxThreadContext(...)` is false for the selected item, so `rootTags` is `[]` by construction even though the item is a reply inside a thread that does address an agent.

In both cases the reply is sent with whatever `mentionPubkeys` the composer itself resolved — which is empty when the `@Agent` text was typed rather than picked from the mention picker, because the Inbox item's `mentionPubkeysByName` map only covers names already seen in the loaded window.

## Expected

An Inbox reply to a thread addresses the same agents as the identical reply sent from the channel view:

- the thread root is **fetched**, not looked up best-effort in the rendered window; a failure to load it should be surfaced (or the reply deferred), never degraded into an empty audience;
- a typed `@Name` that resolves to a channel member/agent produces the matching `p` tag, independently of whether the name happened to be in the loaded window.

Happy to provide the full event ids and pubkeys privately.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.