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> (cherry picked from commit 13e1245bbd042fb6d1afa6cf54152e839d9fe400) Signed-off-by: Logan Johnson <loganj@squareup.com> (cherry picked from commit e5e77d88c3eb87360aac8771d17389abee831d3f) Signed-off-by: Logan Johnson <loganj@squareup.com>
4.8 KiB
Remote mention preparation and publication
Owned relay agents can be selected and invited without local runtime custody. The picker and preparation phase evaluate policy but may admit an owned nonmember. Publication separately refreshes authorization for the exact eventual destination, including a newly created DM. Ownership is not membership and cached picker evidence is never publication authorization.
Selections are intent: a vanished/revoked key must fail visibly, retain the draft and send nothing, rather than silently dropping a recipient. Captured agent keys survive composer clearing, media upload, edits and asynchronous preparation. A failed local inventory read cannot veto authenticated relay identities or admit stale local runtimes. Locally managed runtime readiness remains a separate existing path; remote identities never gain synthetic local management records.
Chat offers explicit Invite or reference-only send without inviting. Failed adds, revoked policy, failed final authorization and cancellation preserve recoverable drafts. Standalone forum sends report authorization failures, but standalone forum invitation is a subsequent change reusing this phase contract.
Native discovery prerequisite: docs/owned-agent-discovery.md (PR6).
Regression coverage: agentAutocompleteEligibility.test.mjs,
agentMentionRevalidation.test.mjs, useMentionSendFlow.helpers.test.mjs,
submitMessageEdit.test.mjs, mentions.spec.ts, and
remote-owned-mentions.spec.ts. The new remote browser fixtures use a single-word
name deliberately: mention separator behavior belongs to the independent PR1.
NIP-OA establishes ownership, not physical hosting, availability, or lifecycle control. Final native queries do not provide an atomic relay transaction with message publication. Independent review of both native and publication boundaries is required before landing.
Invitation intent and cancellation
Each chat Invite owns one synchronous pending latch and abort signal, covering preparation, inventory, adds and the eventual publication continuation. Escape, navigation/unmount, reference-only selection or a replacement prompt invalidates that attempt. Clearing the prompt when promoting it to send is not cancellation; the signal remains live through final validation and queued media completion. Check cancellation after asynchronous preparation and before subsequent mutations (including nested local readiness), and again before publication. A completed add cannot be undone, but its late response cannot revive cancelled message intent. The pending state includes preparation, disabling both Invite and reference-only buttons. Cancellation after optimistic clearing restores the captured draft and exact mention refs without overwriting newer edits.
useMentionSendFlow.cancellation.test.mjs drives the actual hooks with React
StrictMode and deferred dependencies; remote-owned-mentions.spec.ts covers
visible pending, Escape/retry and route navigation at deferred IPC boundaries.
Source draft ownership
Invitation intent belongs to one visit of the effective persistence key and channel, not just the mounted composer or destination channel. Same-channel thread changes and A → B → A invalidate the original visit. The visible owner gates optimistic clear, editor recovery and pending state. Storage recovery instead consults the captured source visit's authored revision even after that visit exits; losing visible ownership never revokes an authored deletion. The lifecycle retains a per-visit revision record through its captured accessor, so B's edits cannot authorize or suppress A's recovery. Preflight recovery and sent-draft cleanup use that same source authority. Invalidation makes recovery durable synchronously, before a later visit can load or edit the source draft; late async completion cannot revive that recovery or release a newer attempt's latch.
The editor's authored revision distinguishes an intentional edit → clear from an optimistic empty composer. Programmatic send clear/recovery runs inside the draft lifecycle's restoration boundary, so it does not mark the source as authoritatively deleted. Exact selected mention refs are captured before asynchronous preparation. Persona preparation similarly consumes captured selections and returns resolved refs, writing them into the editor only while the original visit/revision remains current. Normal persona creation/reuse and ordinary destination-bound background sends retain their existing behavior; accepted membership is never rolled back.
Recovery still compares stored content/media/refs rather than implementing a versioned draft database. Final membership/policy reads are not atomic with send, and cancellation cannot retract an already dispatched publication. Standalone forum transport-failure binding recovery and native compatibility remain separate review/follow-up boundaries.