fix(desktop): authorize remote mentions at publication - #7124
Conversation
Extract preparation, exact destination checks and retained recipient intent from #7114, independently of labels and profile presentation. 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>
Signed-off-by: Logan Johnson <loganj@squareup.com>
Remote-owned mention routing — PR7Mock IPC browser capture at Invite an owned relay agent without local inventoryPreparation offers the existing chat Invite/reference-only choice; ownership alone is not publication authorization. Publish after current membership and policy checksThe sent message retains the exact RemoteScout recipient. Unauthorized add preserves the draftAn actor authorization error stays visible and sends no message. Policy rejection preserves the draftThe channel-add policy error stays visible without silently dropping the recipient. |
Keep invitation intent alive through preparation, add, and publication, while cancelling dismissal, navigation and replacement. Retain cleared drafts on late cancellation and cover async boundaries with real React and browser regressions. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
B1: preparation is visibly pending and cancellableAt repair |
Invalidate same-channel thread changes and returning visits before late invitation continuations can clear or recover over another draft. Separate authored editor revisions from optimistic clear, capture exact selections before preparation, and bind resolved persona refs to that captured draft. Cover retained-host navigation, recovery, media, and persona preparation; sanitize screenshot stems only. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Bind authored revisions to captured lifecycle visits instead of the visible editor. Apply source authority to cancellation and preflight recovery and sent-draft cleanup, while keeping editor ownership separate. Cover reviewer deletion reproduction, queued files, supersession, return visits, and actual thread-switch persistence. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Use the captured submission revision for sent-draft storage authority, including ordinary destination-bound sends that leave before optimistic clear. Add a discriminating regression for that lifecycle boundary. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Keep authored intent in the scoped draft store independently of value deletion. Supersede recovery, sent cleanup and lifecycle persistence across reentry and remount while preserving ordinary destination-bound sends and untouched optimistic recovery. Keep editability and automatic prefix restoration programmatic. Exercise the real store, React lifecycle transition matrix and retained browser editor. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
A frozen logical tail can report physical bottom before buffered live rows are released. Keep the existing catch-up action visible while pending rows remain so a shared thread message can enter the parent timeline after closing the thread. Preserve scroll anchoring and explicit catch-up behavior. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>





🤖
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
@(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.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, base branch
split/owned-agent-discovery, which lets Desktop find and verify owned agents independently of this device. 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; here those composers only gain visible authorization errors. Same-name selection/binding fixes (#7133) and mention spacing (#7128) are not included.
Extracted from #7114 (historical source
98fe33ec). Behavior and draft-recovery contract · Originating discussion.Testing
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 · Pending-state capture. 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. CI passed for this head. No product tests were rerun for this description-only edit.
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.