diff --git a/protocol/diagrams/duplex-messaging/queue-rotation-fast.mmd b/protocol/diagrams/duplex-messaging/queue-rotation-fast.mmd
index 75887dd0b..952729f4a 100644
--- a/protocol/diagrams/duplex-messaging/queue-rotation-fast.mmd
+++ b/protocol/diagrams/duplex-messaging/queue-rotation-fast.mmd
@@ -5,13 +5,18 @@ sequenceDiagram
participant S as Server that has A's send queue (B's receive queue)
participant B as Bob
- A ->> R': NEW: create new queue (allow SKEY)
- A ->> S: SEND: QADD (R'): send address of the new queue(s)
+ A ->> R': NEW: create new queue (SKEY allowed)
+ A ->> S: SEND: QADD (R')
S ->> B: MSG: QADD (R')
- B ->> R': SKEY: secure new queue
- B ->> R': SEND: QTEST
- R' ->> A: MSG: QTEST
- A ->> R: DEL: delete the old queue
- B ->> R': SEND: send messages to the new queue
- R' ->> A: MSG: receive messages from the new queue
-
\ No newline at end of file
+ B ->> R: SEND: messages (also scheduled on R')
+ R ->> A: MSG: messages
+ B ->> R': SKEY: authorize B as sender
+ B ->> R': SEND: confirmation (establishes R' secret)
+ R' ->> A: MSG: confirmation (A secures R')
+ B ->> R': SEND: held copies (deduped), then new messages
+ R' ->> A: MSG: messages
+ B ->> R: SEND: remaining tail, then QEND
+ R ->> A: MSG: QEND
+ B ->> R': SEND: QEND
+ R' ->> A: MSG: QEND
+ A ->> R: DEL: delete the current queue
diff --git a/protocol/diagrams/duplex-messaging/queue-rotation-fast.svg b/protocol/diagrams/duplex-messaging/queue-rotation-fast.svg
index 823074823..77b986d75 100644
--- a/protocol/diagrams/duplex-messaging/queue-rotation-fast.svg
+++ b/protocol/diagrams/duplex-messaging/queue-rotation-fast.svg
@@ -1,3 +1,3 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/rfcs/2026-08-09-fast-queue-rotation.md b/rfcs/2026-08-09-fast-queue-rotation.md
index 83dcb2904..d5cb3cf55 100644
--- a/rfcs/2026-08-09-fast-queue-rotation.md
+++ b/rfcs/2026-08-09-fast-queue-rotation.md
@@ -1,10 +1,10 @@
---
Proposed: 2026-08-09
Protocol: agent-protocol v8
-Diagram: ./diagrams/duplex-messaging/queue-rotation-fast.svg
+Diagram: ../protocol/diagrams/duplex-messaging/queue-rotation-fast.svg
---
-# Fast queue rotation (redundant delivery)
+# Fast queue rotation
## Problem
@@ -14,33 +14,38 @@ cannot move away from a failed server.
## Solution
-When both agents support v8, rotation is redundant delivery rather than a switch. The initiator adds
-a new queue with `QADD`; from that point the peer writes every message to both the current queue and
-the new queue, and secures the new queue in parallel. Once the new queue is secured the peer writes
-new messages to it alone, while the current queue delivers whatever was already scheduled on it and a
-final `QEND`, and is then removed. The recipient already drops duplicate messages, so the order of
-delivery and which queue delivers a given message do not matter, provided every message arrives on at
-least one queue. There is no boundary and no flip.
+Both the current rotation and v8 add a queue, deliver to both queues while the rotation is in
+progress, and remove the old queue; the recipient drops duplicates in both. The main difference is where
+the new queue's secret is established. In the current rotation it is established over the current
+queue, by `QKEY`, so it cannot complete when the current server is down. In v8 the peer establishes the
+new queue's secret over the new queue itself — a confirmation it sends on R' — so establishing the
+secret no longer depends on the current queue, and the rotation completes even when the current server
+is down.
-Rotation away from a dead current server works because every message is also scheduled on the new
-queue: the recipient reads it there. A dead new queue does not stop delivery either, because the
-current queue keeps delivering until the new one is secured.
+v8 also starts writing to both queues earlier: from the moment the queue is added, including the
+current queue's not-yet-delivered backlog. So the initiator adds the new queue with `QADD`; from that
+point the peer writes every message to both the current queue and R'. Once R' is secured the peer
+writes new messages to it alone, while the current queue delivers whatever was already scheduled on it
+and a final `QEND`, and is then removed. Because the recipient drops duplicates, neither the order of
+arrival nor which queue carries a message matters, provided each message arrives on at least one queue
+— with one exception, the confirmation, which is always the first message on R'. A dead new queue does
+not stop delivery either, because the current queue keeps delivering until R' is secured.
Roles: A initiates (its receiving queue rotates; A receives on the new queue R'). B is the peer (B
holds the sending queue to A, secures R', and delivers to both).
-Sequence (as drawn in the diagram):
+Sequence:
- A -> R' : create new queue (messaging mode, SKEY allowed)
- A -> S -> B : QADD(R') (over A's sending queue; A's current server untouched)
- B : from now, schedule every message on both the current queue and R'
- B -> both : messages (current queue and R', duplicates dropped by A)
- B -> R' : SKEY (B secures R')
- B -> R' : confirmation (empty; establishes R' secret; first message on R')
- B : R' secured — new messages now go to R' only
- B -> current : remaining tail, then QEND(current)
- B -> R' : QEND(current), then new messages
- A : on QEND, delete the current queue; keep receiving on R'
+ A -> R' : create new queue (messaging mode, SKEY allowed)
+ A -> S -> B : QADD(R') (over A's sending queue; A's current server untouched)
+ B : from QADD, schedule every message and the current backlog on both queues
+ B -> current : deliver the scheduled messages (R' holds its copies while securing)
+ B -> R' : SKEY (authorize B as sender)
+ B -> R' : confirmation (empty; establishes R' secret; first message on R')
+ B -> R' : deliver R''s held copies (A dedups), then new messages to R' only
+ B -> current : deliver the remaining tail, then QEND(current)
+ B -> R' : QEND(current)
+ A : on QEND, delete the current queue; keep receiving on R'
## Confirmation
@@ -58,10 +63,11 @@ additionally encrypted with the double ratchet, so rotation does not advance the
`QEND` names a queue to remove and is delivered on both queues. On receipt the recipient deletes the
named queue; on send the peer removes its sending queue of that address. `QEND` is a general
-queue-removal message — the peer can remove either queue with it — so rotation is the addition of a
-queue (`QADD`) followed by the removal of a queue (`QEND`), with no distinct switch step. Delivering
-`QEND` on the removed queue is best effort; the copy on the surviving queue removes it and reaches the
-recipient even when the removed server is dead.
+queue-removal message — the peer can remove either queue with it — so on the wire a rotation is the
+addition of a queue (`QADD`) and the later removal of the replaced one (`QEND`), each an ordinary
+operation on the queue set rather than a `QTEST`-style completion. Delivering `QEND` on the removed
+queue is best effort; the copy on the surviving queue removes it and reaches the recipient even when
+the removed server is dead.
## Per-queue secret
@@ -75,7 +81,7 @@ Fast rotation runs only when the connection's agreed agent protocol version is 8
chooses it. Otherwise the `QKEY`/`QUSE` exchange is used. `QEND` is defined at version 8 and is only
sent during fast rotation, so peers below version 8 never receive it.
- new A / new B : fast (QADD, confirmation, redundant delivery, QEND)
+ new A / new B : fast (QADD, confirmation on R', QEND)
new A / old B : slow (old B returns QKEY; new A keeps the QKEY/QUSE handling)
old A / new B : slow (agreed version below 8; new B returns QKEY)
old A / old B : slow
@@ -87,5 +93,5 @@ confirmation on R' followed later by `QEND`.
The initiator keeps reading messages on the new queue and removes the current queue when `QEND`
arrives there, without waiting for the current server. Nothing is lost, because every message is
-scheduled on the new queue as well; the only cleanup that a dead current server delays is the deletion
+scheduled on the new queue; the only cleanup that a dead current server delays is the deletion
of its queue, which is retried a bounded number of times and then abandoned.