Change:
5.3.1. <ins> When a server receives an Initial packet containing duplicate CRYPTO data, it can assume the client did not receive all of the server's CRYPTO data sent in Initial packets, or the client's estimated RTT is too small.  When a client receives Handshake or 1-RTT packets prior to obtaining Handshake keys, it may assume some or all of the server's Initial packets were lost. To speed up handshake completion under these conditions, an endpoint MAY send a packet containing unacknowledged CRYPTO data earlier than the PTO expiry, subject to address validation limits; see Section 8.1 of QUIC-TRANSPORT. Peers can also use coalesced packets to ensure that each datagram elicits at least one acknowledgement.  For example, clients can coalesce an Initial packet containing PING and PADDING frames with a 0-RTT data packet and a server can coalesce an Initial packet containing a PING frame with one or more packets in its first flight. 5.3.2. </ins> When a PTO timer expires, a sender MUST send at least one ack- eliciting packet as a probe, unless there is no data available to send.  An endpoint MAY send up to two full-sized datagrams containing

Discussion:
When the second duplicate client Initial is received, the server MAY retransmit the contents of it's Initial to speed up the handshake. I'm not sure we want to document only this case, or have a larger section about optimizations to speed recovery during the handshake.
That could be an attack vector since you could send small invalid handshake packets. Not sure how efficient such an attack would be and we don't try too hard to avoid problems at this stage, as long as isn't an efficient amp attack.
I think the latest text looks great. Thanks NAME for putting it together.
After thinking it through, this is a good choice. The downside is the client might have a bad initial PTO. But without this optimization, upon receipt of another client hello I'll just send more ceritificate data that was blocked by the amplification limit, data that is probably useless if the server hello has been lost. Far better for me to send the server hello again instead.
This issue has consensus and I'm happy with the text, so I'm going to merge it and we can work on a follow-up editorial PR in
This tracks any follow-ups to
Is there any such follow-up? If not, close this?
I think this is probably OBE and we should close this.
Generally, the server's first flight (of a 1-RTT connection attempt) has a single Initial packet and the rest is made up of 1 or more Handshake packets. If the UDP datagram containing the Initial packet is lost, the server only ends up retransmitting it based off the default RTT based PTO timer. If/when the client receives the Handshake packets that it can't decrypt (because the Initial was lost) then it has a (possible) signal that the server has responded, but a packet was lost. The client could use this info to immediately retransmit its Initial. If/when the server receives this, it could use this info to retransmit its Initial.
Isn't this a special case of the EMPTY_ACK frame discussed earlier?
Yes, but the problem is the worst in this case, because the server doesn't have an RTT estimate, so it can't have an accurate PTO for retransmitting.

Once it has received a single ACK, the PTO becomes a lot more accurate, and falling back to the PTO is a lot less painful.
This problem also occurs when the server receives 0-RTT packets it cannot decrypt. In that case, it would be ideal if it could do something to indicate something was received but not processed. I guess it could send a PING in an Initial packet as an alternative to EMPTY_ACK? I sent out a PR that I believe covers the most important points you mention. PTAL.
I think the problems here are: Receiving a retransmit client Initial does not necessarily indicate a loss. It could simply be the case that the actual RTT is greater than the client's initial RTT. Do we want the server to retransmit packets in that case? Note that a client might use a small initial RTT when it is connecting to a server that it has previously connected to. How the server detects a retransmission will become complicated if we adopt . Considering these aspects, I might be weakly inclined to addressing the issue using an explicit signal, defined either within v1 or an extension.
I think this falls into the category of black-holing invalid packets as they might easily come from an unwanted source.
I don't believe complicates things substantially, because if only one UDP datagram is lost, then you would expect to receive an ACK in a relatively short period(no ack delay) of time and loss recovery could function quite well.
Does this need to be standardized? Or does it fall in the range of heuristics that applications may do, but don't need to be specified.
Of course the handshake packet that you receive can be a bunch of random bytes sent by an attacker...
Discussed in Cupertino. NAME to update based on discussion.
The proposed "fix" could lead to a deadlock where the server consumes its entire congestion window without making progress. If the server receives too many Initial packets (bad RTT estimate at the client, say), then it will send lots of data without getting an ACK. As suggested, this is just an optimization, so limiting the number of times this optimization can be used might avoid that problem.
Discussed in ZRH. No change since Cupertino.
Apparently this has consensus. NAME is ready?

My only problem is that I wouldn't know how to detect duplicate CRYPTO data from a cursory read. Normally you'd feed the data to a TLS blackbox and it would not necessarily provide the information needed. The alternative seems to be to inspect CRYPTO frames, but who is to say that duplicate data is always framed the same?
NAME detecting duplicate CRYPTO data is definitely implementation dependent, so I don't want to describe that in the recovery doc.
This is definitely an improvement. Thanks for writing it up! In addition to this, should we have text that says the client should/may immediately retransmit its initial packet if it gets a handshake packet it can't decrypt?