Skip to content

feat(desktop): invite owned agents from standalone forums - #7125

Merged
loganj merged 5 commits into
mainfrom
split/forum-agent-invitation
Sep 4, 2026
Merged

feat(desktop): invite owned agents from standalone forums#7125
loganj merged 5 commits into
mainfrom
split/forum-agent-invitation

Conversation

@loganj

@loganj loganj commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

In Desktop's standalone Forums, selecting an owned agent from another device could leave a post or reply unsendable if the agent had not joined the forum. This adds Invite / Cancel to the send flow so you can resolve membership without leaving your draft.

  • Invite checks response policy and your permission to add members, adds the agent to the forum, waits for refreshed membership, then rechecks authorization before posting to the original destination. Membership is forum-wide, not limited to one post.
  • Cancel / Escape keeps the text, attachments and selected recipients for retry. Unlike chat's Do nothing / Send anyway, this dialog has no reference-only send choice. Invite is disabled while pending; Cancel remains available.
  • Leaving the source post/reply cancels its pending invitation, even if you return. Errors remain visible, focus returns to the initiating editor when appropriate, and late completion cannot resume a cancelled post or interfere with a newer attempt.
  • A rejected send restores text, uploaded media and exact selected recipients to the source draft only if no newer edit, deletion, upload intent or send supersedes it. Clipboard verification settles before recipient capture, with stale edits/navigation fenced out.

Related issue

Targets main after #7124 merged. This PR reuses its publication checks and draft protection; the five forum commits have been replayed unchanged onto the merged parent. Owned-agent discovery (#7122) is already merged. Split from #7114.

Forum creation/templates, channel-less Notes and local-agent management are unchanged. Duplicate-name binding from #7133 is already merged and retained by this stack. Inviting does not start a remote agent or promise that it is online or will reply.

Testing

Forum composer lifecycle tests, including clipboard-settlement cases, and TypeScript/changed-file formatting checks passed after the restack. Earlier invitation, focus and transport-recovery browser coverage is retained, not claimed as a fresh full browser run on this head. See live CI for current-head results. Browser evidence uses mock IPC; no full local just ci pass or native/live-relay validation is claimed.

To try it: open a forum post or reply, select an owned nonmember agent and send. Cancel, then retry without reselecting; Invite should add that agent before posting. Deny the add to check the visible error and retained draft. Navigate away/back during a pending invitation or rejected send; no stale publication or overwrite of a newer draft should occur.

Forum invitation with Invite and Cancel

Earlier mock-browser capture, not current-head runtime proof. Error and successful-post captures; no before-state/native capture available.

Limits: cancellation cannot undo accepted membership changes or dispatched posts; authorization and publication are not atomic. Recovery is same-window, subject to browser storage limits, and is not a durable in-flight send journal: reload/crash can lose a pending snapshot. Cross-window coordination and in-flight upload custody are unchanged. The parent's legacy member-agent compatibility does not establish ownership for nonmember invitations.

@loganj
loganj force-pushed the split/forum-agent-invitation branch 2 times, most recently from 6858c35 to 9a5e328 Compare August 31, 2026 17:47
@loganj

This comment has been minimized.

loganj added a commit that referenced this pull request Aug 31, 2026
@loganj
loganj force-pushed the split/forum-agent-invitation branch 3 times, most recently from 4cd9736 to ec5fd56 Compare August 31, 2026 19:36
@loganj
loganj force-pushed the split/forum-agent-invitation branch 2 times, most recently from d92df38 to 8eba950 Compare August 31, 2026 20:53
@loganj
loganj marked this pull request as ready for review August 31, 2026 21:50
@loganj
loganj requested a review from a team as a code owner August 31, 2026 21:51

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 8eba950a86be1a4d0d5847315d140c862eabee01 against base 7ffead0f8ae128782991153054abd388e4ff04d9.

Two author-actionable defects remain:

  1. [P1] Same-forum thread navigation can publish the preserved reply to the thread the user left. ForumComposer suspends submission while the Invite dialog is open, but useForumMentionPreparation defines freshness only by channelId. ForumView reuses the same unkeyed thread panel/composer when selectedPostId changes within a forum. If a user begins a reply/invite on thread A, navigates to thread B while the add is pending, and the add completes, the continuation remains current and invokes the submitter captured for A while B is visible. Besides surprising publication, the accepted membership side effect cannot be rolled back. The new navigation test covers only a channel change, so it does not exercise this boundary.

    Author action: bind the pending attempt to the source visit/thread identity (or remount the reply composer by selectedPostId) and add an A→B same-forum deferred-add regression proving no reply publishes to either thread and draft recovery remains owned by the correct source. This also restores the source-visit contract documented in docs/remote-mention-routing.md.

  2. [P2] The newly exposed forum Invite dialog is not keyboard/focus or async-error accessible. An exact-head Playwright probe observed document.activeElement === BODY after the alert dialog opened and again after Escape dismissed it; the changing invitation error had no alert/live-region semantics. The implementation uses ordinary Buttons rather than the available Radix AlertDialogCancel / AlertDialogAction primitives, and the dynamically inserted error is an unannotated paragraph. Keyboard users therefore do not enter the decision controls or return to the preserved composer, and assistive technology is not notified when Invite fails.

    Author action: use the alert-dialog action/cancel primitives or explicit autofocus/restore handling, make the changing error an alert/live region, and add regression coverage for initial safe focus, Escape/Cancel focus restoration, and error announcement. Preserve the shared chat behavior as well.

Validation at this exact, clean head: git diff --check passed; just desktop-check and just desktop-typecheck passed; pnpm build:e2e passed; isolated Playwright forum-agent-invitation.spec.ts passed 8/8. Required CI reported green, including Desktop Core, four Desktop Smoke shards, relay/integration jobs, macOS build, Semgrep, zizmor, and DCO. The broader just desktop-test reviewer run was interrupted after roughly five minutes without an observed assertion failure, so that is a confidence gap rather than author rework. Native packaged Tauri/accessibility observation also remains a reviewer/release verification gap, not a separate author defect.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review verdict: request changes

Reviewed base 7ffead0f8ae128782991153054abd388e4ff04d9 through exact live head 8eba950a86be1a4d0d5847315d140c862eabee01, integrating both assigned lanes. Two author-actionable defects remain.

1. Same-forum thread navigation does not invalidate a pending reply invitation

ForumComposer retains the captured submission continuation while Invite is pending (desktop/src/features/forum/ui/ForumComposer.tsx:225-251), while useForumMentionPreparation scopes freshness only to channelId (desktop/src/features/forum/ui/useForumMentionPreparation.ts:30-31,50-52,117-120). ForumView reuses the unkeyed thread panel/composer when selectedPostId changes (desktop/src/features/forum/ui/ForumView.tsx:131-166; ForumThreadPanel.tsx:331-339). Navigating thread A→B in one forum therefore leaves the attempt current; completing Invite can resume the captured reply to A while B is displayed.

Author action: bind pending preparation to source visit/thread identity (or remount by selectedPostId) and add a held-add A→B regression proving no reply publishes and draft recovery remains attached to the correct source.

2. The Invite dialog breaks keyboard-focus and error-announcement behavior

NonMemberMentionDialog does not use the Radix action/cancel primitives or explicit autofocus handling, and its dynamic failure text has no alert/live-region semantics (desktop/src/features/messages/ui/NonMemberMentionDialog.tsx:35-85). An exact-head production-build probe observed BODY focused after open and after Escape; the visible async error had no alert/live attributes. This newly exposed forum journey therefore neither moves focus safely into the modal, restores it to the preserved composer, nor announces invitation failure to assistive technology.

Author action: establish safe initial focus and focus restoration, expose changing failure text as an alert/live region, and add regressions for open, Escape/Cancel, and failure semantics while preserving the shared chat behavior.

Verification

Focused forum E2E passed 8/8; check/typecheck and E2E build passed. The incomplete broad local suite and absent packaged-native journey are reviewer/release confidence gaps, not additional author rework.

— :bot: Jude’s code review agent

@loganj
loganj force-pushed the split/remote-mention-routing branch from 7ffead0 to 1144465 Compare September 2, 2026 16:55
@loganj
loganj force-pushed the split/forum-agent-invitation branch from 8eba950 to 6781210 Compare September 2, 2026 17:45
loganj added a commit that referenced this pull request Sep 2, 2026
@loganj

This comment has been minimized.

@loganj

loganj commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Response to your original exact-head review (both body findings; there are no inline review threads to resolve).

Addressed in 67812105430e5d4d3f82bf952e67f55839de0702, on routing base 1144465d00273cf74b7c22544ae5a3299bd98560:

  1. P1 source-visit publication: keyed composer/thread visits and generation/pending-owner fences invalidate A when navigating to B—even within one forum and on A→B→A. Deferred-add production/browser regressions assert no stale reply publication and source-owned draft restoration; old completion cannot release a newer retry. Accepted membership is not rolled back.
  2. P2 dialog accessibility: safe initial Cancel focus, source-checked deferred composer restoration after Escape/Cancel, enabled forum cancellation during add, and changing errors with role=alert. Existing chat Do nothing/Send anyway is retained. Forum + shared focus browser evidence is 16/16; shared browser baseline 67/67.

Independent review found a subsequent repair regression (failed dispatched A after returning with no new intent); source-key recovery now preserves text/uploaded media/exact refs without overwriting newer intent or replaying send. Final desktop 6016/6016; four old-source failure/new-source pass recovery assertions; six independent edge probes and expected media-snapshot mutation failure. Three new browser cases eventually pass: the initial empty-fill deletion fixture failed, then Select All/Backspace plus pre-release emptiness assertion passed the isolated rerun. That history is preserved, not called a clean initial 3/3.

Latest-source TypeScript and normal OSS/internal frontend artifact matrix pass; final scoped static/size/E2E build evidence reused where exact. Updated PR body records provenance, prepared screenshots and limitations. Packaged-native accessibility, live relay/signed ownership and root security authorization remain separate; no formal review is dismissed. Requesting fresh formal review of this exact head, not treating local scoped approval as yours.

@loganj

loganj commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Response to the integrated review verdict, separately preserving the response to both original review bodies. GitHub exposes no inline thread for either finding, so these linked comments are the response records; no formal review is resolved/dismissed by the author.

The repair is 67812105430e5d4d3f82bf952e67f55839de0702, base 1144465d00273cf74b7c22544ae5a3299bd98560.

  • Finding 1: ForumView/ForumComposer keyed source visits and hook generation/pending-object ownership stop held-add A→B/A→B→A continuations from publishing. Production-seam and real-editor/mock-IPC browser regressions cover source-owned recovery, cancellation/retry, stale completion and no replay. The additional independently found dispatched-reply regression is repaired under shared source-key authority; newer edits/deletion/new sends win.
  • Finding 2: NonMemberMentionDialog explicitly focuses the safe action and announces async failure (role=alert); deferred close restoration checks the captured connected source editor. Escape/Cancel and shared chat are covered. Cancel stays available during a forum add.

Final 6016 desktop tests pass. Reused 16 forum/focus and 67 shared browser passes for unchanged scope; three new recovery browser cases eventually pass (two initially, deletion after correcting an empty-fill fixture with actual keyboard deletion and an emptiness assertion). Independent 6/6 edge probes plus a failing media-snapshot mutant make the cleanup/recovery claim falsifiable. Latest normal OSS/internal artifact matrix + TypeScript pass; scoped static, file-size and E2E build passed. All committed blobs match the reviewed frozen candidate; no publisher source edits.

The body includes exact evidence, prior-failure history and limits. This resolves the author-actionable implementation work, not native/release confidence or root/routing security gates. Fresh exact-head technical review and hosted CI are still required.

@loganj
loganj requested a review from jedwards27 September 2, 2026 17:48

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent — APPROVE exact head 67812105430e5d4d3f82bf952e67f55839de0702 against base 1144465d00273cf74b7c22544ae5a3299bd98560.

Both assigned lanes found no remaining author-actionable defect.

The changed head closes the prior blockers:

  • Pending forum reply intent is keyed by source visit/thread identity. Same-forum A→B→A navigation, held membership add, late completion, cancellation, recovery, and publication retain the captured source authority rather than resuming against the wrong thread.
  • The Invite alert dialog now gives safe initial focus to Cancel/Do nothing, restores focus to the current source editor after Cancel or Escape, and exposes asynchronous failure with role="alert".
  • Authorization is checked before membership add and again against refreshed membership before publication. Draft identity, attachments, references, retry, and shared-chat behavior remain coherent.

Exact-head evidence:

  • Production-seam lifecycle suite: 21/21.
  • Production-build Playwright forum invitation suite: 19/19.
  • Desktop check, typecheck, file-size validation, direct TypeScript typecheck, E2E production build, and git diff --check: PASS.
  • Completed hosted DCO, Desktop builds, integration shards, relay artifact, token guard, and security scanners: green. Desktop Core and four smoke shards were still pending at the final snapshot; no PR-caused required-gate failure was observed.

Confidence gaps, not author action:

  • Packaged Tauri plus real screen-reader behavior was not observed. Verification owner: release/native QA for an optional assistive-technology smoke.
  • Native/real-relay membership-add-to-publication atomicity cannot be proven by browser mocks. Verification owner: native integration/release validation; no reproducible defect was found.
  • Remaining hosted Desktop Core/smoke completion is owned by CI. Author action: none unless a current-head required gate fails.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review verdict: approve

Reviewed base 1144465d00273cf74b7c22544ae5a3299bd98560 through exact live head 67812105430e5d4d3f82bf952e67f55839de0702, integrating both assigned systems/integration and product/UI/accessibility lanes. The two defects from the prior head are resolved; no author-actionable defect remains.

  • Source authority is now keyed to the forum post/thread visit. Pending invitation and publication continuations are invalidated across same-forum A→B navigation, while source-key draft recovery preserves the exact content, attachments, and selected identity without overwriting newer A or B intent or replaying publication.
  • Membership add and final publication authorization use the captured channel, with a fresh authoritative revalidation after membership refresh. Cancellation invalidates late add/validation completion; transport failure recovery follows the same source-key ownership rules.
  • The alert dialog places initial focus on the safe action, restores the current source editor after Cancel or Escape, keeps cancellation available while Invite is pending, and exposes asynchronous failures with role="alert". Shared-chat behavior remains covered.

Exact-head evidence: production-seam lifecycle tests passed 21/21 in my clean checkout; the product lane's production-build Playwright run passed 19/19 with invite/error/sent screenshots visually inspected; desktop check, typecheck, file-size validation, and production E2E build passed across the assigned lanes. At submission time, macOS and integration checks had passed; Desktop Core and four smoke shards were still running without a reported failure. Their completion remains CI-owned and requires no author action unless they expose a PR-caused failure.

Residual confidence gap: packaged Tauri with a real relay and real screen reader was not observed. Author action: none. Verification owner: release/QA for an optional packaged-native assistive-technology and add→publish smoke.

— :bot: Jude’s code review agent

loganj added a commit that referenced this pull request Sep 2, 2026
🤖

## Summary

An agent you own could be missing from **New message → To:** and
**Channel members → Add people and agents** on a machine that has never
managed it. This PR lets those existing lists find your agent without
requiring a shared channel first. Desktop now checks records proving you
own it, rather than looking only at agents in channels you've already
joined.

**No new screen or control is added.** For example, an agent with
verified ownership and **Who can send instructions → Only me (default)**
can now appear even with no shared channels. Each screen still applies
its existing access rules; this does not make every discovered agent
selectable everywhere.

| Screen / control | Before | After this PR alone |
| --- | --- | --- |
| **New message → To:** recipient picker | An owned agent absent from
this machine and shared-channel bot lists could be missing. | Its named
**agent** row can appear; selecting it adds a recipient chip. This is
recipient selection, not a guarantee that a later message will reach or
wake the agent. |
| **Channel members → Add people and agents** | The same agent could be
missing from **Not in this channel** search results. | Its row can
appear with the existing **Add** button. If you can add members, that
button submits the existing channel-membership request; finding the row
alone changes no membership. |
| **Stream / forum composer → @ suggestions** | An owned agent already
in the channel under an ordinary member role could be missing from agent
suggestions. | Its actual membership is recognized without requiring the
bot role. Agents not managed on this device still need membership in
that channel. |
| **Pulse → Agents** | An agent absent from both local management and
the server's agent list was omitted from the count and author lookup. |
The count and feed's author lookup can include it; notes appear only if
it has published them. |

Being listed does **not** mean the agent is online, add it to a channel,
or grant local Start/Edit controls. For agents not managed on this
device, global **Search** still excludes those configured for “Only me”,
and DM @ selection is not added here. DM @ selection and message-driven
nonmember invitation are addressed in
[#7124](#7124); the standalone forum
**Invite / Cancel** flow is in
[#7125](#7125).

<details>
<summary>Ownership and membership checks</summary>

A discovery lead is not proof: the latest agent profile must have a
valid signature and exactly one valid ownership attestation—the owner's
signed link to that agent. Its response policy must be signed by that
verified owner; an invalid latest policy cannot restore an older
permission. Membership comes separately from the latest server-signed
roster, including removals.

Existing profile cards, owner labels and agent-avatar shapes also use
this stricter verification: malformed or forged evidence must not supply
ownership/agent classification on its own. Valid ownership was already
recognized; no profile-picture or badge design changes.

Attestation time conditions apply to the signed event's timestamp, not a
live expiry timer. Existing legacy compatibility and builds requiring
verified owner policy retain their respective rules. Discovery and
sending remain separate operations, not an atomic permission check.

</details>

### Review corrections

- When runtime and owner policy overlap, **explicit online/away/offline
from the verified latest runtime is retained**. Policy still supplies
ownership/permissions; claimed runtime membership is not restored.
Missing/unrecognized status stays unknown, and invalid latest policy
cannot revive runtime permissions.
- Discovery without runtime evidence is now **unknown**, not offline:
native conversion, both IPC adapters, Pulse, Projects and
profile/session consumers preserve that distinction. Unknown has no
status dot and is not promoted to a deployed/running agent.
- Both relay-only picker paths retain the authenticated owner, including
the existing **managed by you** label. The analogous global Search
projection is fixed without changing its existing “anyone” filter.
- Authorized stored profile activity remains visible when liveness
becomes unknown/absent or the active turn ends. History reads do not
start a live subscription, grant access, or imply current availability.

### Related issue

Independent base: `main`. Child:
[#7124](#7124), then
[#7125](#7125). Extracted from
[#7114](#7114), retained as historical
source (`98fe33ec`).

[Behavior
contract](https://github.com/block/buzz/blob/3a56d17824522580fe04cae463b54f4c7ba66021/docs/owned-agent-discovery.md).
Originating [Buzz
discussion](buzz://message?channel=f7a9536a-1738-4bad-a888-b3ea25010ef1&id=7aa1f0ab23dce514bd8a0221441cf005bf428914621171472b79747c50820848)
· channel `f7a9536a-1738-4bad-a888-b3ea25010ef1`.

### Testing

Current candidate: `3a56d17824522580fe04cae463b54f4c7ba66021`, a
four-file native/test/doc runtime-status repair atop published
`ae23c1c9680a881cee7eed94e259bf15bf8ce3f7`. Branch ancestry is main
`1c8321cd08feb597f8bcff5195c21148fb3e98ed`; refreshed main
`0e878664b08cdf7fb2d89d940bc2aa92cdc485f7` adds only the independent
CI-workflow split. Read-only mergeability succeeds; this is not a tested
merged-tree claim.

**Local CI attempt and continuation (not an uninterrupted green run):**
the new exact-head `just ci` passed formatting/static checks, workspace
and Tauri clippy, workspace Rust tests, **5,910 desktop tests**, desktop
production build and Tauri check. Its native main target finished
**3,073 passed / 1 failed / 19 ignored** (exit 101):
`cheap_discovery_reports_absent_before_any_forced_probe` saw a
process-global login-shell counter of 2 instead of 0. The counter
includes unrelated version/adapter probes whose tests do not hold the
failed test's PATH mutex; no managed-agent discovery implementation
changed in the runtime repair. The unchanged failing test then passed
**three isolated invocations**. Only the failed native workspace lane
was retried with `RUST_TEST_THREADS=1 just desktop-tauri-test`: **3,074
main-target tests passed / 19 ignored**, all additional workspace
targets passed (exit 0). The previously unrun `just web-build
mobile-test` tail then passed (exit 0; **2,019 mobile tests**). Earlier
successful lanes were reused; no source/guard changes or blanket CI
rerun. The original failure and all diagnostic/retry logs are retained.

- **71 native `nostr_convert` tests pass**, including seven new
production merge regressions: online/away/offline, missing/invalid
status, policy-only, status-less latest replacement and forged latest
replacement. Before production repair, those seven yielded **4 failures
/ 3 passing controls**.
- Reused frontend evidence from `ae23c1c9` (frontend is unchanged):
Desktop TypeScript and isolated E2E build pass; **9 browser tests / 0
retries**, covering both relay-only picker journeys and seven adjacent
stop-control regressions. Real UI with mock Tauri IPC, not live
relay/native webview.
- Earlier `ae23c1c9` local `just ci` passed without failures, including
3,067 native main-target tests / 19 ignored and 2,019 mobile tests; not
substituted for the new source gate above.
- Reused unchanged repair evidence: **17 real-store/hook history
regressions**, **161 focused tests**, and independent **9 mounted
owner/bot/identity revocation/regrant transitions** with zero hook-phase
native calls. The regression was falsified before repair (14 failures, 3
controls).
- Signed local-server fixtures cover discovery with no local/shared
record, ordinary-role membership, forged ownership, invalid signatures,
duplicate authentication, wrong-owner/latest-invalid policy, revoked
membership and wrong destinations. These establish native data checks,
not a live agent response.

GitHub checks and renewed technical/security review must apply to the
current published head; earlier-head green checks are not
replacement-head proof. Local source review is not formal
code-owner/latest-push approval or exact-range security authorization. A
green security workflow with substantive review skipped is not security
clearance.

### Screenshots

#### Relay-only picker evidence —
`ae23c1c9680a881cee7eed94e259bf15bf8ce3f7`

These cropped rows come from the two real production picker journeys in
[`owned-agent-discovery.spec.ts`](https://github.com/block/buzz/blob/ae23c1c9680a881cee7eed94e259bf15bf8ce3f7/desktop/tests/e2e/owned-agent-discovery.spec.ts),
using mock Tauri IPC with **no local agents and no user-search
duplicate**. The fixture supplies verified-owner data and unknown
availability; the browser test checks its presentation, not native
signature verification. Both exact-tip journeys pass without retries. No
live relay, native webview, invitation, delivery or wakeup is claimed.

Before the repair, both relay-only candidate constructors discarded the
owner, so the existing “managed by you” label was absent. These are
after-repair captures; no before image was captured.

#### New Message → To
The relay-only agent retains its authenticated owner label.


![new-message-owner](https://raw.githubusercontent.com/block/buzz/536c6d3c90776cf85b1d5ce58666f2c8ad518829/pr-7122--new-message-owner.png)

#### Channel members → Add people and agents
The matching result retains “managed by you” beside the existing Add
action; the test does not click Add or claim membership changed.


![member-add-owner](https://raw.githubusercontent.com/block/buzz/536c6d3c90776cf85b1d5ce58666f2c8ad518829/pr-7122--member-add-owner.png)

---------

Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
@loganj
loganj force-pushed the split/remote-mention-routing branch from 1144465 to e66b949 Compare September 3, 2026 02:54
@loganj
loganj force-pushed the split/forum-agent-invitation branch from 6781210 to 870a2a1 Compare September 3, 2026 03:15
@loganj

loganj commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

Rebased forum descendant — fresh head 870a2a1eb06a24f401dd5ead3e85b101d63255d4

Replayed the three forum commits onto #7124 at e66b949cabcf06f2871e610f6ad3e3136b1c2f16. The only range-diff is contextual smoke registration; invitation/publication authorization, navigation cancellation and source-draft recovery behavior are unchanged. This remains a dependent PR, not an independent main-based change.

Exact-head local evidence:

  • Full Desktop JS suite: 6124 passed.
  • Forum + remote-owned-mention Chromium journeys: 37 passed, using mock IPC (not live-relay proof).
  • Desktop checks/typecheck/E2E build passed, with the existing shared dependency-metadata warning.
  • Full Tauri workspace test command: 3253 passed, 20 ignored. Initial compile exceeded the 600-second execution window; incremental rerun completed successfully. The original timeout is retained.
  • just ci was attempted again: root formatting/clippy passed; Desktop's pnpm wrapper attempted dependency reconciliation and stopped because it would purge the shared modules without a TTY. No purge or peer-file changes were made. This is not a full local CI pass; fresh hosted checks remain required.

All 13 outgoing objects retain the configured signatures and required attribution/DCO. Explicit lease publication replaced 67812105; no merge, review dismissal, or gate bypass. Requesting fresh automated review of the rebased head. Existing substantive review history remains intact.

@loganj
loganj requested a review from jedwards27 September 3, 2026 03:16
Mushkrot pushed a commit to Mushkrot/buzz that referenced this pull request Sep 4, 2026
🤖

## Summary

An agent you own could be missing from **New message → To:** and
**Channel members → Add people and agents** on a machine that has never
managed it. This PR lets those existing lists find your agent without
requiring a shared channel first. Desktop now checks records proving you
own it, rather than looking only at agents in channels you've already
joined.

**No new screen or control is added.** For example, an agent with
verified ownership and **Who can send instructions → Only me (default)**
can now appear even with no shared channels. Each screen still applies
its existing access rules; this does not make every discovered agent
selectable everywhere.

| Screen / control | Before | After this PR alone |
| --- | --- | --- |
| **New message → To:** recipient picker | An owned agent absent from
this machine and shared-channel bot lists could be missing. | Its named
**agent** row can appear; selecting it adds a recipient chip. This is
recipient selection, not a guarantee that a later message will reach or
wake the agent. |
| **Channel members → Add people and agents** | The same agent could be
missing from **Not in this channel** search results. | Its row can
appear with the existing **Add** button. If you can add members, that
button submits the existing channel-membership request; finding the row
alone changes no membership. |
| **Stream / forum composer → @ suggestions** | An owned agent already
in the channel under an ordinary member role could be missing from agent
suggestions. | Its actual membership is recognized without requiring the
bot role. Agents not managed on this device still need membership in
that channel. |
| **Pulse → Agents** | An agent absent from both local management and
the server's agent list was omitted from the count and author lookup. |
The count and feed's author lookup can include it; notes appear only if
it has published them. |

Being listed does **not** mean the agent is online, add it to a channel,
or grant local Start/Edit controls. For agents not managed on this
device, global **Search** still excludes those configured for “Only me”,
and DM @ selection is not added here. DM @ selection and message-driven
nonmember invitation are addressed in
[block#7124](block#7124); the standalone forum
**Invite / Cancel** flow is in
[block#7125](block#7125).

<details>
<summary>Ownership and membership checks</summary>

A discovery lead is not proof: the latest agent profile must have a
valid signature and exactly one valid ownership attestation—the owner's
signed link to that agent. Its response policy must be signed by that
verified owner; an invalid latest policy cannot restore an older
permission. Membership comes separately from the latest server-signed
roster, including removals.

Existing profile cards, owner labels and agent-avatar shapes also use
this stricter verification: malformed or forged evidence must not supply
ownership/agent classification on its own. Valid ownership was already
recognized; no profile-picture or badge design changes.

Attestation time conditions apply to the signed event's timestamp, not a
live expiry timer. Existing legacy compatibility and builds requiring
verified owner policy retain their respective rules. Discovery and
sending remain separate operations, not an atomic permission check.

</details>

### Review corrections

- When runtime and owner policy overlap, **explicit online/away/offline
from the verified latest runtime is retained**. Policy still supplies
ownership/permissions; claimed runtime membership is not restored.
Missing/unrecognized status stays unknown, and invalid latest policy
cannot revive runtime permissions.
- Discovery without runtime evidence is now **unknown**, not offline:
native conversion, both IPC adapters, Pulse, Projects and
profile/session consumers preserve that distinction. Unknown has no
status dot and is not promoted to a deployed/running agent.
- Both relay-only picker paths retain the authenticated owner, including
the existing **managed by you** label. The analogous global Search
projection is fixed without changing its existing “anyone” filter.
- Authorized stored profile activity remains visible when liveness
becomes unknown/absent or the active turn ends. History reads do not
start a live subscription, grant access, or imply current availability.

### Related issue

Independent base: `main`. Child:
[block#7124](block#7124), then
[block#7125](block#7125). Extracted from
[block#7114](block#7114), retained as historical
source (`98fe33ec`).

[Behavior
contract](https://github.com/block/buzz/blob/3a56d17824522580fe04cae463b54f4c7ba66021/docs/owned-agent-discovery.md).
Originating [Buzz
discussion](buzz://message?channel=f7a9536a-1738-4bad-a888-b3ea25010ef1&id=7aa1f0ab23dce514bd8a0221441cf005bf428914621171472b79747c50820848)
· channel `f7a9536a-1738-4bad-a888-b3ea25010ef1`.

### Testing

Current candidate: `3a56d17824522580fe04cae463b54f4c7ba66021`, a
four-file native/test/doc runtime-status repair atop published
`ae23c1c9680a881cee7eed94e259bf15bf8ce3f7`. Branch ancestry is main
`1c8321cd08feb597f8bcff5195c21148fb3e98ed`; refreshed main
`0e878664b08cdf7fb2d89d940bc2aa92cdc485f7` adds only the independent
CI-workflow split. Read-only mergeability succeeds; this is not a tested
merged-tree claim.

**Local CI attempt and continuation (not an uninterrupted green run):**
the new exact-head `just ci` passed formatting/static checks, workspace
and Tauri clippy, workspace Rust tests, **5,910 desktop tests**, desktop
production build and Tauri check. Its native main target finished
**3,073 passed / 1 failed / 19 ignored** (exit 101):
`cheap_discovery_reports_absent_before_any_forced_probe` saw a
process-global login-shell counter of 2 instead of 0. The counter
includes unrelated version/adapter probes whose tests do not hold the
failed test's PATH mutex; no managed-agent discovery implementation
changed in the runtime repair. The unchanged failing test then passed
**three isolated invocations**. Only the failed native workspace lane
was retried with `RUST_TEST_THREADS=1 just desktop-tauri-test`: **3,074
main-target tests passed / 19 ignored**, all additional workspace
targets passed (exit 0). The previously unrun `just web-build
mobile-test` tail then passed (exit 0; **2,019 mobile tests**). Earlier
successful lanes were reused; no source/guard changes or blanket CI
rerun. The original failure and all diagnostic/retry logs are retained.

- **71 native `nostr_convert` tests pass**, including seven new
production merge regressions: online/away/offline, missing/invalid
status, policy-only, status-less latest replacement and forged latest
replacement. Before production repair, those seven yielded **4 failures
/ 3 passing controls**.
- Reused frontend evidence from `ae23c1c9` (frontend is unchanged):
Desktop TypeScript and isolated E2E build pass; **9 browser tests / 0
retries**, covering both relay-only picker journeys and seven adjacent
stop-control regressions. Real UI with mock Tauri IPC, not live
relay/native webview.
- Earlier `ae23c1c9` local `just ci` passed without failures, including
3,067 native main-target tests / 19 ignored and 2,019 mobile tests; not
substituted for the new source gate above.
- Reused unchanged repair evidence: **17 real-store/hook history
regressions**, **161 focused tests**, and independent **9 mounted
owner/bot/identity revocation/regrant transitions** with zero hook-phase
native calls. The regression was falsified before repair (14 failures, 3
controls).
- Signed local-server fixtures cover discovery with no local/shared
record, ordinary-role membership, forged ownership, invalid signatures,
duplicate authentication, wrong-owner/latest-invalid policy, revoked
membership and wrong destinations. These establish native data checks,
not a live agent response.

GitHub checks and renewed technical/security review must apply to the
current published head; earlier-head green checks are not
replacement-head proof. Local source review is not formal
code-owner/latest-push approval or exact-range security authorization. A
green security workflow with substantive review skipped is not security
clearance.

### Screenshots

#### Relay-only picker evidence —
`ae23c1c9680a881cee7eed94e259bf15bf8ce3f7`

These cropped rows come from the two real production picker journeys in
[`owned-agent-discovery.spec.ts`](https://github.com/block/buzz/blob/ae23c1c9680a881cee7eed94e259bf15bf8ce3f7/desktop/tests/e2e/owned-agent-discovery.spec.ts),
using mock Tauri IPC with **no local agents and no user-search
duplicate**. The fixture supplies verified-owner data and unknown
availability; the browser test checks its presentation, not native
signature verification. Both exact-tip journeys pass without retries. No
live relay, native webview, invitation, delivery or wakeup is claimed.

Before the repair, both relay-only candidate constructors discarded the
owner, so the existing “managed by you” label was absent. These are
after-repair captures; no before image was captured.

#### New Message → To
The relay-only agent retains its authenticated owner label.

![new-message-owner](https://raw.githubusercontent.com/block/buzz/536c6d3c90776cf85b1d5ce58666f2c8ad518829/pr-7122--new-message-owner.png)

#### Channel members → Add people and agents
The matching result retains “managed by you” beside the existing Add
action; the test does not click Add or claim membership changed.

![member-add-owner](https://raw.githubusercontent.com/block/buzz/536c6d3c90776cf85b1d5ce58666f2c8ad518829/pr-7122--member-add-owner.png)

---------

Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
(cherry picked from commit 434dafe)
@loganj
loganj force-pushed the split/remote-mention-routing branch from e66b949 to a49846a Compare September 4, 2026 15:00
@loganj
loganj force-pushed the split/forum-agent-invitation branch from 14d30d1 to 416a0f3 Compare September 4, 2026 15:01

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent — APPROVE at exact head 416a0f387020f562da7bb4ad6cb30f83b6545201 against base a49846a738c2ce2eae28eeea3d5e627ca97b6ba4.

No unresolved author-actionable defect remains after independent systems/integration and product/UI review.

The changed-head delta adds a post-settlement composer-revision/visit-authority fence before invitation preparation. The integrated review verified source/thread ownership, exact-recipient held membership add, fresh final authorization, cancellation and late-completion invalidation, navigation/A→B→A isolation, dispatch-failure draft/media recovery, accessible Invite/Cancel/Escape and focus/error behavior, and persistence compatibility. Removing the new fence made the targeted stale clipboard-settlement regression fail; the exact head was restored and clean before verdict.

Exact-head evidence integrated: Desktop units 6,352/6,352; forum lifecycle 25/25; production-bound forum invitation Playwright 19/19; desktop check, typecheck, production build, file-size, git diff --check, four hosted smoke shards, Windows/macOS builds, integration, DCO, Semgrep, and zizmor passed.

Confidence gaps, not author rework: Desktop Core remained in progress without observed failure at submission; native screen-reader and real-shell observation were not run. Author action: none unless Core fails causally. Verification owner: CI/integration for Core completion; native accessibility/release QA for optional platform observation.

Any new head invalidates this approval.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent — APPROVE at exact head 416a0f387020f562da7bb4ad6cb30f83b6545201 against base a49846a738c2ce2eae28eeea3d5e627ca97b6ba4.

No unresolved author-actionable defect was found in the changed-head review.

The re-review range-diffed from previously reviewed head 14d30d18a00fb2a5c0cd46b2847a8842a6bb140c and found one new semantic patch: the composer now captures draft authority before pending pasted-mention settlement and fences continuation on unmount, navigation/return, or authored revision change before invitation preparation (desktop/src/features/forum/ui/ForumComposer.tsx:342-363). The surrounding integration paths retain exact selected-recipient and bot-role membership adds, fresh authorization before publish, cancellation/late-completion invalidation, and source-key/revision-owned draft and media recovery (useForumMentionPreparation.ts:35-168, ForumComposer.tsx:374-404, useForumDraftRecovery.ts:25-93). No persistence schema or native storage format changes were introduced.

Exact-head verification on clean worktrees:

  • just desktop-check — passed
  • just desktop-typecheck — passed
  • just desktop-test — 6,352/6,352 passed
  • just desktop-build — passed
  • production-bound forum invitation Playwright suite — 19/19 passed
  • targeted forum lifecycle suite — 25/25 passed
  • causal mutation removing the new post-settlement fence failed the intended stale clipboard-settlement regression, then the exact head was restored cleanly

The production-bound suite covers Invite/Cancel/Escape, focus restoration, visible error and keyboard Retry behavior, exact successful p tags, revoked/finally unauthorized recipients, navigation while pending, A→B→A during add and publish, reference-only shared chat, and dispatch-failure draft/media recovery. Screenshots were coherent.

Residual confidence gaps do not require author rework: native VoiceOver/NVDA announcement timing and a real native GUI/IPC pass were not directly observed; browser E2E uses mock IPC as documented in docs/forum-agent-invitation.md:20-24. Optional native accessibility/release QA owns that assurance. At final review submission, all completed applicable hosted checks were green, while Desktop Domain / Desktop Core remained in progress; required CI must complete successfully before integration.

Any new head invalidates this approval.

loganj added a commit that referenced this pull request Sep 4, 2026
…7133)

## Summary

Selecting two people or agents named Scout could replace the first
recipient with the second even though the message still looked right.
This binds each selection to its exact identity: the first keeps
`@Scout`, and a conflicting selection gets `@Scout (<full public key>)`.
Removing one no longer removes or redirects the other.

- Reuse the existing **@ suggestion list**; team selection and automatic
agent addressing reserve and reuse distinct labels too. Typing an
ambiguous name manually shows an instruction to use the picker and
preserves the draft without publishing—in chat, edits and standalone
forums.
- Share literal mention matching across recipient extraction, removal,
display and editing so a shorter name cannot claim another recipient's
longer or qualified label.
- Rebuild authored references when a message is edited, and use the
latest authorized snapshot when reopening or forwarding.
Rendering/editing can recover qualified identities only from the
message's recorded references, not from a key typed into its body.
Unresolvable historical names remain literal rather than guessed
recipients.
- Wrap full-key labels within narrow/zoomed layouts while keeping their
complete accessible label and ordinary mention icons. Edit activation
waits for the action menu's focus cleanup before focusing the editor.

### Related issue

Targets `main`; mention spacing (#7128) is already merged. Split from
#7114. This is independent of the #7124#7125 remote-invitation stack
and does not expand agent eligibility or invitation permissions. The
separate Enter-selection suffix issue remains tracked in #7253.

### Testing

The desktop unit suite and focused mock-Chromium checks passed on the
published integration candidate, including pending-paste selection,
edit/forwarding, copy and narrow-layout cases; formatting, types and
frontend builds passed. On `0b3b18c0`, 64 focused trust/paste/selection
unit tests and six mock-Chromium tests passed with zero browser retries,
including actual timeline chip copy → fresh channel paste → send and
mismatched-key rejection; TypeScript, changed-file Biome and an isolated
E2E build passed. The broader browser run had copy failures before the
focused repairs and is not claimed as wholly green. See [live
CI](https://github.com/block/buzz/pull/7133/checks) for current-head
results. No full local `just ci` pass, native/live-relay or
cross-browser validation is claimed.

To try it: select two same-name recipients, remove one, send, then
edit/reopen and forward; only the intended identities should remain.
Type an ambiguous name without choosing a suggestion and check that
sending retains the draft with an error. Inspect full-key labels in a
narrow window at 150% text size, and open Edit and type immediately.

![Ambiguous mention keeps the chat
draft](https://raw.githubusercontent.com/block/buzz/c48053209b36b3b1bf7197cf2d606d27b48a27c0/pr-7133--ambiguous-general.png)

![Full-key label in a narrow, zoomed
composer](https://raw.githubusercontent.com/block/buzz/ac262f00de6fe3860bff2f87dc0e98165ed6b651/pr-7133--layout-1.5-composer.png)

*Earlier mock-browser captures, not current-head runtime proof. No new
before-state capture; screenshots alone do not prove recipient
delivery.*

**Clipboard trust:** generated full-key-qualified mentions now retain
their exact recipient after copy/paste when the full key matches the
clipboard record and community directory/profile state independently
vouches for the base alias, including numeric collision suffixes. A
qualifier alone does not establish trust. Arbitrary historical labels
still cannot always be reconstructed.

---------

Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-authored-by: Bad Janet <150b20bdf6130418df9239dd1bd082c71612c8d653b47c277200365b9be215dc@buzz>
@loganj
loganj force-pushed the split/remote-mention-routing branch from a49846a to 0b303f8 Compare September 4, 2026 16:04
@loganj
loganj force-pushed the split/forum-agent-invitation branch from 416a0f3 to b4dd19c Compare September 4, 2026 16:04
jedwards27
jedwards27 previously approved these changes Sep 4, 2026

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE
Reviewed: 0b303f805e4420eae682087555075c5a7472e40e..b4dd19cfae1fbeb8ffb93c049f3338af688f42e2 (exact head b4dd19cfae1fbeb8ffb93c049f3338af688f42e2)
Risk: high — forum publication now invites selected non-member agents and must preserve exact recipient authorization, draft ownership, cancellation, and failure recovery across asynchronous membership and transport boundaries.

Behavior/contracts traced: source-key/revision ownership before clipboard settlement; exact intended-agent capture; membership revalidation before add and again before publish; cancellation/navigation/unmount fencing; failed-dispatch recovery of text, completed media, and exact mention refs; shared non-member-dialog keyboard/focus behavior; legacy-safe draft persistence.

Findings: no blocking or non-blocking defect found. The restacked five-patch series was reviewed fresh; three patches are patch-identical to the prior series, while the material delta adds the originating-visit clipboard fence and reconciles the parent head's exact-recipient smoke coverage.

Author action: none.
Verification owner: CI/release owns required-gate disposition and optional packaged-Tauri/native assistive-technology observation.

Validation at matching clean head:

  • just desktop-check — PASS (repository diagnostics only)
  • just desktop-typecheck — PASS
  • just desktop-test — PASS, 6,434/6,434
  • just desktop-build — PASS, including protected-artifact matrix
  • focused composer lifecycle — PASS, 25/25
  • desktop/tests/e2e/forum-agent-invitation.spec.ts — PASS, 19/19
  • focused production-built smoke including mention-recipients.spec.ts — PASS, 39/39
  • causal mutation removing the pre-invitation clipboard fence made its regression test fail (2 !== 0); restoring exact head returned the tree clean
  • git diff --check 0b303f805e4420eae682087555075c5a7472e40e...HEAD — PASS

Required smoke reconciliation: hosted shards 2 and 3 are red, but the failures do not establish a PR-caused defect. The PR-specific forum suite passed 19/19 in the same shard-2 job and independently at exact head. Shard 2's final failures are broad message-edit/attachment/history cases; the historical-recipient case passed in the focused 39/39 rerun, and the attachment failure was already classified flaky after retry. Shard 3's persistent-agent-audience failure is identical at the same test line on the exact base run 33891898259; that base run also failed unrelated profile/workflow/navigation/thread tests across shards, while the candidate failures additionally span onboarding and overscroll files outside this PR's changed production surface. This is base-wide/broad-shard harness instability, not causal evidence against the forum change. The red required checks still own merge readiness; they do not create author rework without a causal defect.

Manual/native evidence: browser-bound production-build interaction covers dialog focus/Escape, alert semantics, cancellation, invite denial/failure, exact recipient routing, navigation, A→B→A ownership, and transport recovery. Packaged Tauri, live relay, VoiceOver, and NVDA were not directly observed.

Residual risk: native announcement timing and signed packaged-runtime ownership remain unobserved. Any head change invalidates this approval.

Base automatically changed from split/remote-mention-routing to main September 4, 2026 16:35
@loganj
loganj dismissed jedwards27’s stale review September 4, 2026 16:35

The base branch was changed.

loganj added a commit that referenced this pull request Sep 4, 2026
🤖

## Summary

In Buzz Desktop, you could own an agent running on another device but be
unable to mention it in a channel where it had not yet joined: it was
filtered out before you could invite it. A selected agent could also
disappear from the message's recipients when permissions changed. This
lets you select an eligible agent in the existing **@ menu**, invite it
from the message composer, and send to that agent—or see an error and
keep your draft rather than silently sending without it.

#### Where the experience changes

| Screen / control | Before → after |
| --- | --- |
| A channel's **Message #…** composer, or a message's **Reply in thread
to …** composer | Type `@` (or use the existing @ button), choose your
agent, write the message and press **Send message**. An owned agent not
yet in the channel can now reach the existing **“Mention people outside
this channel?”** dialog when its response settings allow you to address
it. |
| That dialog's **Invite** button | Previously the membership
requirement could block the agent before the invitation. Now Invite
checks permission to add it, adds it as an agent member of the
**channel** (not just the thread), then rechecks membership and response
permission before sending the waiting message. An agent already in the
channel needs no invitation. |
| Existing direct message, or the new-message screen with the **To:**
field | A mention is checked against the conversation the message will
actually enter, including a newly created direct message, rather than
the old or not-yet-created destination. This does not add an Invite
control to direct messages. |
| Editing a message / sending attachments | The selected agent remains
part of the send or edit attempt through attachment upload and the final
permission check. Lost permission produces a visible error instead of
dropping that recipient. |

**Invite is not the only chat choice.** The existing **Do nothing**
button sends the message *without inviting or notifying the nonmembers*;
their names remain references in the text. Where you cannot invite, that
choice is labelled **Send anyway**. To abandon the send instead, dismiss
the dialog with Escape. Invitation actions are disabled while
preparation is pending, preventing duplicate clicks.

**Leaving and returning must not resurrect a cancelled send.** Switching
threads or leaving the composer cancels its pending invitation, even if
you return to the same thread. Cancellation before dispatch sends no
message; an accepted membership change cannot be automatically undone.
An ordinary send without a pending invitation remains bound to its
original destination rather than following you into another
conversation.

**Failed sends must not overwrite your next draft.** If you leave a
thread, return and replace or deliberately clear its draft while an
older send is pending, the older failure cannot restore deleted text,
recipients or files; success cannot erase the newer draft—even if its
text is identical. An untouched draft cleared automatically for sending
remains recoverable on failure. This protection also covers reopening
the composer and starting a newer send.

The channel timeline also keeps its existing **new-messages / Jump to
latest** button available when newer messages are waiting to be
displayed. For example, after sharing a reply to the channel and closing
the thread panel, you can click the catch-up button to reveal buffered
messages. Closing the thread does **not** guarantee the shared row
appears automatically or force you away from reading history.

### Related issue

Built on [#7122](#7122), base branch
`split/owned-agent-discovery`, which lets Desktop find and verify owned
agents independently of this device. Current integration head:
`1144465d00273cf74b7c22544ae5a3299bd98560`, built on exact published
root `3a56d17824522580fe04cae463b54f4c7ba66021`. Root #7122 has its own
CI and security gates; this PR must not land ahead of that dependency.
Finding an agent is not channel membership, online status or a promise
of a reply. This PR changes what the existing message controls can do
with those agents; it adds no profile, presence, cloud marker or remote
start/stop UI.

Standalone forum post/reply **Invite / Cancel** is added separately in
[#7125](#7125); here those composers
only gain visible authorization errors. Same-name selection/binding
fixes ([#7133](#7133)) and mention
spacing ([#7128](#7128)) are not
included.

Extracted from [#7114](#7114)
(historical source `98fe33ec`). [Behavior and draft-recovery
contract](https://github.com/block/buzz/blob/1144465d00273cf74b7c22544ae5a3299bd98560/docs/remote-mention-routing.md)
· [Originating
discussion](buzz://message?channel=f7a9536a-1738-4bad-a888-b3ea25010ef1&id=7aa1f0ab23dce514bd8a0221441cf005bf428914621171472b79747c50820848).

### Testing

![Channel composer after Send: RemoteScout is not a channel member;
Invite adds it before sending, while Do nothing sends without inviting
or notifying
it](https://raw.githubusercontent.com/block/buzz/b20345da0bd648ecbc78988637c89893a33ca2f3/pr-7124--remote-invite.png)

*Earlier candidate, mock desktop browser: the existing channel dialog
now reachable for an eligible owned agent on another device. The two
buttons have different send outcomes; Do nothing is not Cancel.*
[Success and denial
captures](#7124 (comment))
· [Pending-state
capture](#7124 (comment)).
These show the relevant UI, not live agent availability, native
authorization or the later draft-storage/catch-up repairs. No
before-state screenshot is available.

Existing coverage exercises exact recipients, invitation
rejection/cancellation, new direct-message destinations, uploads, edits,
thread re-entry and stored-draft deletion. The timeline regression
checks the shared reply becomes visible using the available catch-up
action.

**Integration validation (2026-09-02):** independently reviewed the
routing delta onto root `3a56d178`: seven original patches unchanged;
two reconciliations retain generic publication-error toasts alongside
authorization errors and retain non-authored editability updates. Added
two production-hook regression tests (normal and queued-media
publication) requiring visible generic error, recovered draft and
released pending state.

- Writer validation: **5,995 Desktop tests**, **42 focused tests**, **22
mock-IPC browser journeys** (18 routing, 2 root provenance, 2
destination binding), and **1 voice-note failure journey** passed; lint,
types, size guards and E2E build also passed.
- The broad suite ran before the final formatting-only test amendment,
not as an exact-final-head rerun. Independent AST comparison confirmed
that amendment is semantics-preserving; **4 fresh assertions at final
`1144465d`** passed. Publication rechecked final-head TypeScript,
amended-test formatting and `git diff --check` successfully. No new full
repository `just ci` run is claimed.
- Browser tests use an isolated E2E build and **mock IPC**, not live
relay/native authorization. Historical screenshots above are explicitly
earlier UI evidence, not exact-head runtime certification. Packaged
Tauri/live-relay behavior was not independently witnessed.
- **Published-head gates:** [current CI
run](https://github.com/block/buzz/actions/runs/33657948560) and
[renewed exact-head formal review
request](#7124 (comment))
must clear before landing. [Earlier CI
run](https://github.com/block/buzz/actions/runs/33438436438) and the two
earlier approvals cover `7ffead0f`, not this new head. Root CI/security
clearance remains separate; the independent scoped integration approval
is not merge authorization.

To try it: in a channel or thread, select an owned nonmember agent,
Send, then Invite or Escape and retry. Deny the add or revoke its
response permission before sending: expect a visible error and
recoverable draft, not a message missing the agent. During a pending
send, return to the source thread, edit or clear the draft, then leave
again: late completion must not overwrite that choice.

**Limits:** permission checks and sending are separate operations;
cancellation cannot retract a dispatched message. Draft protection is
same-window, not new cross-window deletion synchronization. Standalone
forum transport failure can still restore text/media without the exact
selected recipients. Native compatibility is inherited: open-source
builds may still recognize a valid legacy, self-declared agent already
in the channel when verified ownership is absent or rejected; that does
not establish ownership or unlock this owned-nonmember invitation path.
Invalid policy from a verified owner is still rejected. No agent
response is guaranteed.

---------

Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
loganj and others added 5 commits September 4, 2026 12:46
Reuse phase-aware preparation, authorized add and final destination authorization; retain selected drafts on cancellation and failure.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
Keep policy strings and assertions unchanged while replacing invalid filename characters in the screenshot stem.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
…sport

Bind invitation continuations to a keyed source visit, retain cancellable retry drafts, and restore safe dialog focus with announced errors. Recover rejected dispatched replies under shared source-key authority without overwriting newer authored intent or replaying publication. Add production-seam lifecycle and browser regressions.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
Preserve the inherited clipboard wait through restack and gate its pre-preparation continuation by mounted visit and authored revision. Adapt the real composer harness to the clipboard seam and cover late settlement across edit, navigation, return and unmount.

Signed-off-by: Logan Johnson <loganj@squareup.com>
@loganj
loganj force-pushed the split/forum-agent-invitation branch from b4dd19c to 3da45b8 Compare September 4, 2026 17:02
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is d595806fc3b9c9758992e39b9b51cbb5f55791b0...3da45b81ba82b7cb7186ef0d011715b3f39a361a.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 3da45b81ba82b7cb7186ef0d011715b3f39a361a to authorize a new review.
Any previous review applies only to its recorded range.

@loganj
loganj enabled auto-merge (squash) September 4, 2026 17:07

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE
Reviewed: d595806fc3b9c9758992e39b9b51cbb5f55791b0..3da45b81ba82b7cb7186ef0d011715b3f39a361a (exact head 3da45b81ba82b7cb7186ef0d011715b3f39a361a)
Risk: high — user-authored Forum drafts, exact recipient identity, channel membership mutation, async cancellation, and late publication/recovery all cross one send flow.

Behavior/contracts traced: owned nonmember selection → response-policy and actor authorization → forum-wide add → membership refresh → final authorization → exact p-tag publication; Cancel/Escape, navigation, held add/publication, clipboard settlement, optimistic draft clear, transport rejection, attachment/recipient recovery, newer-intent fencing, focus, and accessible error/retry behavior.

Findings: no blocking or non-blocking code defect found. The five patches are patch-equivalent to the previously reviewed stack after restack. The new clipboard-settlement fence captures the authored revision before awaiting paste binding and refuses stale continuation after unmount or revision change (desktop/src/features/forum/ui/ForumComposer.tsx:342-363). Production-seam mutation of that fence fails the new lifecycle regression, so the guard is causally covered.

Both independent lanes cleared this exact head. Systems review confirmed destination/attempt/mount identity fencing, post-add cache refresh, final authorization, and revision-scoped recovery. Product/UI review exercised post and reply Invite, Cancel/Escape, denial/error retry, policy revocation, navigation, duplicate-name identity preservation, loading/inert state, focus restoration, and visible alerts.

Author action: none.
Verification owner: CI/release gate for the two still-running exact-head jobs; release/native QA for optional real Tauri/VoiceOver and live signed-membership observation.

Validation at matching clean HEAD: Desktop package tests 6,435/6,435; pnpm --dir desktop check; pnpm --dir desktop typecheck; pnpm --dir desktop build:e2e; changed Forum Playwright smoke 19/19; git diff --check; causal clipboard-fence mutation; additional same-name/retry adversarial supplement 19/19. Current hosted checks have no failures; all completed Desktop builds/integration/smoke shards, DCO, Semgrep, and zizmor are green. Desktop Core and smoke shard 4 remained in progress at the final freshness fence.

Manual/native evidence: distinct browser-rendered Invite, success, and failure artifacts were inspected at 1280×720. No real packaged Tauri, VoiceOver/NVDA speech, or live relay membership transaction was independently witnessed.

Residual risk: mock IPC does not prove OS assistive speech or a signed live membership transaction. Renderer crash/reload during an in-flight transport remains explicitly outside this PR's durable-recovery contract (docs/forum-agent-invitation.md:49-52). These are confidence gaps, not author-actionable defects. Any new head invalidates this approval.

— :bot: Jude’s code review agent

@loganj
loganj merged commit e7e2993 into main Sep 4, 2026
57 checks passed
@loganj
loganj deleted the split/forum-agent-invitation branch September 4, 2026 17:33

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent — APPROVE at exact head 3da45b81ba82b7cb7186ef0d011715b3f39a361a against base d595806fc3b9c9758992e39b9b51cbb5f55791b0.

No concrete defect remains.

Integrated review

  • The changed-head delta adds a clipboard-settlement fence: it captures the composer revision before awaiting paste binding and refuses to continue after unmount or an authored revision change (ForumComposer.tsx:342-363). A causal mutation deleting that fence made clipboard settlement after edit cannot prepare another forum draft fail (2 !== 0); restored exact head passed.
  • Invitation candidates are resolved selected Forum agents, excluding managed agents and current members, and are revalidated before membership addition and publication (useForumMentionPreparation.ts:67-169). Membership addition uses the captured channel and awaits member-cache invalidation; final relay-agent validation receives that same destination (channels/hooks.ts:826-864, agentMentionRevalidation.ts:113-145).
  • Attempt, channel, mount, and revision identity fence Cancel/Escape, navigation, late membership/publication completion, newer attempts, and clipboard settlement (useForumMentionPreparation.ts:28-57,121-168, ForumComposer.tsx:342-363).
  • Failed transport recovery snapshots exact text, media, and mention references before optimistic clear, then restores only when keyed/revision ownership is still valid; it does not overwrite newer intent or call a departed editor (ForumComposer.tsx:374-409, useForumDraftRecovery.ts:25-94). Draft authority is relay+identity scoped and reset invalidates retained handles (useDrafts.ts:127-205).
  • The changed Forum E2E journey passed 19/19 twice after a fresh E2E build. It covers post/reply Invite, Cancel, Escape during held membership addition, visible add failures and retry, policy revocation, navigation during held add/publication, A→B→A draft/media/exact-recipient custody, transport failure recovery, and exact publication recipients (desktop/tests/e2e/forum-agent-invitation.spec.ts:109-640).
  • An adversarial supplement added a duplicate-display-name owned agent and retried denied/error states in the same dialog without reselection. All retries published only the selected pubkey. It also verified disabled in-flight Invite, enabled Cancel, inert source form, Escape close, and editor focus restoration.
  • Artifact inspection covered distinct Invite, success, and three failure states. Copy truthfully explains invitation versus draft-preserving Cancel; safe initial focus, role="alert", enabled retry, and preserved intended mention were present (NonMemberMentionDialog.tsx:39-112, ForumComposer.tsx:532-545,608-781).

Exact-head verification

  • pnpm test: 6,435/6,435 pass on the full Desktop package rerun. (An initial run had one failure in unchanged useKnownAgentPubkeys.test.mjs; the required full rerun passed.)
  • pnpm typecheck: pass.
  • just desktop-check: pass; only existing non-fatal warnings outside the PR files.
  • CI=1 pnpm test:e2e -- forum-agent-invitation.spec.ts: 19/19 pass.
  • Differential file-size gate and git diff --check base...HEAD: pass.
  • Hosted required workflow 33898423361: success at exact head, including Desktop Core, all four smoke shards, Windows build, macOS build, and relay/integration gates selected for this diff.
  • GitHub/API/fetched/local head matched; PR is mergeable; no unresolved review threads were found during preflight.

Residual confidence gaps

  • Deterministic browser/mock-IPC validation establishes rendered semantics, focus, keyboard behavior, and exact payloads, but not OS VoiceOver speech or a real signed relay membership transaction. Native ownership/membership enforcement is explicitly outside this frontend PR (docs/forum-agent-invitation.md:20-24). Author action: none. Verification owner: release/native QA with a seeded owned nonmember relay agent.
  • Renderer crash/reload during in-flight transport remains outside this PR’s durable-recovery contract and is documented as such (docs/forum-agent-invitation.md:49-52).

Any head or base movement invalidates this approval pending delta review.

nambse pushed a commit to nambse/buzz that referenced this pull request Sep 4, 2026
…lock#7133)

## Summary

Selecting two people or agents named Scout could replace the first
recipient with the second even though the message still looked right.
This binds each selection to its exact identity: the first keeps
`@Scout`, and a conflicting selection gets `@Scout (<full public key>)`.
Removing one no longer removes or redirects the other.

- Reuse the existing **@ suggestion list**; team selection and automatic
agent addressing reserve and reuse distinct labels too. Typing an
ambiguous name manually shows an instruction to use the picker and
preserves the draft without publishing—in chat, edits and standalone
forums.
- Share literal mention matching across recipient extraction, removal,
display and editing so a shorter name cannot claim another recipient's
longer or qualified label.
- Rebuild authored references when a message is edited, and use the
latest authorized snapshot when reopening or forwarding.
Rendering/editing can recover qualified identities only from the
message's recorded references, not from a key typed into its body.
Unresolvable historical names remain literal rather than guessed
recipients.
- Wrap full-key labels within narrow/zoomed layouts while keeping their
complete accessible label and ordinary mention icons. Edit activation
waits for the action menu's focus cleanup before focusing the editor.

### Related issue

Targets `main`; mention spacing (block#7128) is already merged. Split from
block#7114. This is independent of the block#7124block#7125 remote-invitation stack
and does not expand agent eligibility or invitation permissions. The
separate Enter-selection suffix issue remains tracked in block#7253.

### Testing

The desktop unit suite and focused mock-Chromium checks passed on the
published integration candidate, including pending-paste selection,
edit/forwarding, copy and narrow-layout cases; formatting, types and
frontend builds passed. On `0b3b18c0`, 64 focused trust/paste/selection
unit tests and six mock-Chromium tests passed with zero browser retries,
including actual timeline chip copy → fresh channel paste → send and
mismatched-key rejection; TypeScript, changed-file Biome and an isolated
E2E build passed. The broader browser run had copy failures before the
focused repairs and is not claimed as wholly green. See [live
CI](https://github.com/block/buzz/pull/7133/checks) for current-head
results. No full local `just ci` pass, native/live-relay or
cross-browser validation is claimed.

To try it: select two same-name recipients, remove one, send, then
edit/reopen and forward; only the intended identities should remain.
Type an ambiguous name without choosing a suggestion and check that
sending retains the draft with an error. Inspect full-key labels in a
narrow window at 150% text size, and open Edit and type immediately.

![Ambiguous mention keeps the chat
draft](https://raw.githubusercontent.com/block/buzz/c48053209b36b3b1bf7197cf2d606d27b48a27c0/pr-7133--ambiguous-general.png)

![Full-key label in a narrow, zoomed
composer](https://raw.githubusercontent.com/block/buzz/ac262f00de6fe3860bff2f87dc0e98165ed6b651/pr-7133--layout-1.5-composer.png)

*Earlier mock-browser captures, not current-head runtime proof. No new
before-state capture; screenshots alone do not prove recipient
delivery.*

**Clipboard trust:** generated full-key-qualified mentions now retain
their exact recipient after copy/paste when the full key matches the
clipboard record and community directory/profile state independently
vouches for the base alias, including numeric collision suffixes. A
qualifier alone does not establish trust. Arbitrary historical labels
still cannot always be reconstructed.

---------

Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-authored-by: Bad Janet <150b20bdf6130418df9239dd1bd082c71612c8d653b47c277200365b9be215dc@buzz>
(cherry picked from commit ee883d7)
Signed-off-by: nambse <sefa.esendemir@gmail.com>
nambse pushed a commit to nambse/buzz that referenced this pull request Sep 4, 2026
🤖

## Summary

In Buzz Desktop, you could own an agent running on another device but be
unable to mention it in a channel where it had not yet joined: it was
filtered out before you could invite it. A selected agent could also
disappear from the message's recipients when permissions changed. This
lets you select an eligible agent in the existing **@ menu**, invite it
from the message composer, and send to that agent—or see an error and
keep your draft rather than silently sending without it.

#### Where the experience changes

| Screen / control | Before → after |
| --- | --- |
| A channel's **Message #…** composer, or a message's **Reply in thread
to …** composer | Type `@` (or use the existing @ button), choose your
agent, write the message and press **Send message**. An owned agent not
yet in the channel can now reach the existing **“Mention people outside
this channel?”** dialog when its response settings allow you to address
it. |
| That dialog's **Invite** button | Previously the membership
requirement could block the agent before the invitation. Now Invite
checks permission to add it, adds it as an agent member of the
**channel** (not just the thread), then rechecks membership and response
permission before sending the waiting message. An agent already in the
channel needs no invitation. |
| Existing direct message, or the new-message screen with the **To:**
field | A mention is checked against the conversation the message will
actually enter, including a newly created direct message, rather than
the old or not-yet-created destination. This does not add an Invite
control to direct messages. |
| Editing a message / sending attachments | The selected agent remains
part of the send or edit attempt through attachment upload and the final
permission check. Lost permission produces a visible error instead of
dropping that recipient. |

**Invite is not the only chat choice.** The existing **Do nothing**
button sends the message *without inviting or notifying the nonmembers*;
their names remain references in the text. Where you cannot invite, that
choice is labelled **Send anyway**. To abandon the send instead, dismiss
the dialog with Escape. Invitation actions are disabled while
preparation is pending, preventing duplicate clicks.

**Leaving and returning must not resurrect a cancelled send.** Switching
threads or leaving the composer cancels its pending invitation, even if
you return to the same thread. Cancellation before dispatch sends no
message; an accepted membership change cannot be automatically undone.
An ordinary send without a pending invitation remains bound to its
original destination rather than following you into another
conversation.

**Failed sends must not overwrite your next draft.** If you leave a
thread, return and replace or deliberately clear its draft while an
older send is pending, the older failure cannot restore deleted text,
recipients or files; success cannot erase the newer draft—even if its
text is identical. An untouched draft cleared automatically for sending
remains recoverable on failure. This protection also covers reopening
the composer and starting a newer send.

The channel timeline also keeps its existing **new-messages / Jump to
latest** button available when newer messages are waiting to be
displayed. For example, after sharing a reply to the channel and closing
the thread panel, you can click the catch-up button to reveal buffered
messages. Closing the thread does **not** guarantee the shared row
appears automatically or force you away from reading history.

### Related issue

Built on [block#7122](block#7122), base branch
`split/owned-agent-discovery`, which lets Desktop find and verify owned
agents independently of this device. Current integration head:
`1144465d00273cf74b7c22544ae5a3299bd98560`, built on exact published
root `3a56d17824522580fe04cae463b54f4c7ba66021`. Root block#7122 has its own
CI and security gates; this PR must not land ahead of that dependency.
Finding an agent is not channel membership, online status or a promise
of a reply. This PR changes what the existing message controls can do
with those agents; it adds no profile, presence, cloud marker or remote
start/stop UI.

Standalone forum post/reply **Invite / Cancel** is added separately in
[block#7125](block#7125); here those composers
only gain visible authorization errors. Same-name selection/binding
fixes ([block#7133](block#7133)) and mention
spacing ([block#7128](block#7128)) are not
included.

Extracted from [block#7114](block#7114)
(historical source `98fe33ec`). [Behavior and draft-recovery
contract](https://github.com/block/buzz/blob/1144465d00273cf74b7c22544ae5a3299bd98560/docs/remote-mention-routing.md)
· [Originating
discussion](buzz://message?channel=f7a9536a-1738-4bad-a888-b3ea25010ef1&id=7aa1f0ab23dce514bd8a0221441cf005bf428914621171472b79747c50820848).

### Testing

![Channel composer after Send: RemoteScout is not a channel member;
Invite adds it before sending, while Do nothing sends without inviting
or notifying
it](https://raw.githubusercontent.com/block/buzz/b20345da0bd648ecbc78988637c89893a33ca2f3/pr-7124--remote-invite.png)

*Earlier candidate, mock desktop browser: the existing channel dialog
now reachable for an eligible owned agent on another device. The two
buttons have different send outcomes; Do nothing is not Cancel.*
[Success and denial
captures](block#7124 (comment))
· [Pending-state
capture](block#7124 (comment)).
These show the relevant UI, not live agent availability, native
authorization or the later draft-storage/catch-up repairs. No
before-state screenshot is available.

Existing coverage exercises exact recipients, invitation
rejection/cancellation, new direct-message destinations, uploads, edits,
thread re-entry and stored-draft deletion. The timeline regression
checks the shared reply becomes visible using the available catch-up
action.

**Integration validation (2026-09-02):** independently reviewed the
routing delta onto root `3a56d178`: seven original patches unchanged;
two reconciliations retain generic publication-error toasts alongside
authorization errors and retain non-authored editability updates. Added
two production-hook regression tests (normal and queued-media
publication) requiring visible generic error, recovered draft and
released pending state.

- Writer validation: **5,995 Desktop tests**, **42 focused tests**, **22
mock-IPC browser journeys** (18 routing, 2 root provenance, 2
destination binding), and **1 voice-note failure journey** passed; lint,
types, size guards and E2E build also passed.
- The broad suite ran before the final formatting-only test amendment,
not as an exact-final-head rerun. Independent AST comparison confirmed
that amendment is semantics-preserving; **4 fresh assertions at final
`1144465d`** passed. Publication rechecked final-head TypeScript,
amended-test formatting and `git diff --check` successfully. No new full
repository `just ci` run is claimed.
- Browser tests use an isolated E2E build and **mock IPC**, not live
relay/native authorization. Historical screenshots above are explicitly
earlier UI evidence, not exact-head runtime certification. Packaged
Tauri/live-relay behavior was not independently witnessed.
- **Published-head gates:** [current CI
run](https://github.com/block/buzz/actions/runs/33657948560) and
[renewed exact-head formal review
request](block#7124 (comment))
must clear before landing. [Earlier CI
run](https://github.com/block/buzz/actions/runs/33438436438) and the two
earlier approvals cover `7ffead0f`, not this new head. Root CI/security
clearance remains separate; the independent scoped integration approval
is not merge authorization.

To try it: in a channel or thread, select an owned nonmember agent,
Send, then Invite or Escape and retry. Deny the add or revoke its
response permission before sending: expect a visible error and
recoverable draft, not a message missing the agent. During a pending
send, return to the source thread, edit or clear the draft, then leave
again: late completion must not overwrite that choice.

**Limits:** permission checks and sending are separate operations;
cancellation cannot retract a dispatched message. Draft protection is
same-window, not new cross-window deletion synchronization. Standalone
forum transport failure can still restore text/media without the exact
selected recipients. Native compatibility is inherited: open-source
builds may still recognize a valid legacy, self-declared agent already
in the channel when verified ownership is absent or rejected; that does
not establish ownership or unlock this owned-nonmember invitation path.
Invalid policy from a verified owner is still rejected. No agent
response is guaranteed.

---------

Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
(cherry picked from commit d595806)
Signed-off-by: nambse <sefa.esendemir@gmail.com>
baxen pushed a commit that referenced this pull request Sep 5, 2026
* origin/main:
  fix(desktop): keep packaged frontendDist relative so Windows embeds assets (#7177)
  fix(sidebar): simplify unread indicators and emphasize priority activity (#7134)
  Add generic information-flow control core (#7293)
  feat(buzz-acp): update base prompt; add buzz context and skills to Pi agents (#7335)
  fix(desktop): restore mention chip identity icons (#7338)
  Persist video playback speed preference (#7336)
  Verify ACP relay events before prompt routing (#7010)
  fix(buzz-acp): bound busy-owner hold to prevent cross-channel starvation (#7337)
  feat(desktop): invite owned agents from standalone forums (#7125)
  fix(desktop): authorize remote mentions at publication (#7124)
  fix(acp): rename system tag to agent-instructions (#7332)
  fix(desktop): bind duplicate mention selections to exact recipients (#7133)
  refactor(relay): extract NIP-29 membership authorization (#7285)
  chore(release): release Buzz Desktop version 0.5.22 (#7308)
  feat(desktop): preserve mentions across copy and paste (#7228)
  test(desktop): await Bestie drag and profile hover endpoints (#7294)

Signed-off-by: Fizz <400e8babadcee6a7f420103f10a2849d84c4a9c71d5bd04f3948c814216648a3@buzz.block.builderlab.xyz>
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.

2 participants