Keep timeout-restore queues parked through the same-generation ready path

The deferral-buffer rework routes quarantine restores through a
same-generation ready transition that no longer rebuilds capability
state — but it drained both outbound queues unconditionally there,
bypassing the pending-convergence gate. Honor the restore reason in
that branch too: retrying deferred inbound ciphertext stays (it is
receive-side and safe under restored keys), while queue drains wait for
the convergence retry's establishment exactly as on the new-generation
path. Terminal restores keep draining immediately.

Also pre-drain the establishment's serialized forced announce in the
terminal-restore test so the tap only observes restore-driven traffic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jack
2026-07-26 12:55:14 +02:00
co-authored by Claude Opus 4.8
parent 88e5c9f173
commit 119c0bc8d8
2 changed files with 20 additions and 1 deletions
+16 -1
View File
@@ -4892,8 +4892,23 @@ extension BLEService {
// A quarantined transport restored the same cryptographic
// generation. Its capability proof and announce state never
// became stale; only work queued while outbound keys were paused
// needs one idempotent ready transition.
// needs one idempotent ready transition. Retrying the bounded
// early-ciphertext queue is receive-side and therefore always
// safe under the restored keys.
noisePacketHandler.handleSessionAuthenticated(normalizedPeerID)
#if DEBUG
_test_onPrivateMediaSessionReconciled?(normalizedPeerID)
#endif
if deferOutboundUntilConvergence {
// Timeout-restore: the counterpart may have completed the
// replacement handshake and discarded these keys, so
// encrypting the parked queues here would lose them silently.
// The restore's mandatory convergence retry or any later
// handshake the reconnect policy initiates re-enters this
// transition with a fresh generation and drains them under
// keys both sides hold.
return
}
sendPendingMessagesAfterHandshake(for: normalizedPeerID)
sendPendingNoisePayloadsAfterHandshake(for: normalizedPeerID)
return