Pull-mode httpClient + drainer + parallel RPCs against the same peer
deteriorated after ~10s with `DecryptionError`. Two bugs combined:
- `OutboundQueue.enqueue` woke `drain` waiters with a `since=0`
snapshot, replaying already-processed events into
`Shade.acceptTransferEnvelope` → `manager.decrypt` twice. The
duplicate consumed an already-used skipped key and corrupted the
Double Ratchet receive chain.
- `ratchetDecrypt` then propagated the corruption: a same-DH
message behind the chain with no cached skipped key fell through
to `kdfChainKey` on the ahead state and rewound `chain.counter`,
permanently desyncing the chain.
Fix `OutboundQueue` to honor each waiter's `since`, and harden
`ratchetDecrypt` so any future duplicate fails cleanly without
mutating state. Adds regression coverage at all three layers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>