Change:
promises to never delay acknowledgments of an ack-eliciting packet by more than the indicated value.  If it does, any excess accrues to the RTT estimate and could result in spurious retransmissions from the <del> peer. </del> <ins> peer.  For Initial and Handshake packets, a max_ack_delay of 0 is used. </ins> 5.

Discussion:
Let's do this right and set the value to 0 initially in the transport doc. The "crypto packet" hack is cute, but it's another special case, where this doesn't need a special case, just an initial value.
I think this PR is orthogonal to the question what the default value for this TP is. We use default values to allow peers to skip sending certain transport parameters. This PR is about initializing the maxackdelay variable in the recovery code before we even received the TPs.
NAME I think that using max-ack-delay 0 for crypto packets (to be precise, Initial and Hanshake packets) is not a hack. It's preferable. The problem of respecting TP.maxackdelay for Initial and Handshake packets, once receiving TP from the peer, is that loss recovery would kick in seconds later than they can (note: peer is required to send ACK ASAP).
I see what you mean. I'm still concerned about the special case-y nature of this. Can we segregate by packet number space instead? Is there any reason not to just say that this only applies to Initial and Handshake packets? By my rough reckoning, these should all be acknowledged immediately. Having the transport parameters only apply to 1-RTT (and maybe 0-RTT, which I haven't thought through) is probably right.
I think that just saying that is fine.
I agree. I'll update my PR.
I updated the PR such that maxackdelay is only used for the 1-RTT packet number space.
Note that the ack frames is also not defined before TP's are ready: >The value of the ACK Delay field is scaled by multiplying the encoded value by 2 to the power of the value of the ackdelay_exponent transport parameter set by the sender of the ACK frame.
NAME That is not correct, see URL
OK, but given the latest commit , for Initial, Handshake, does it even make sense to define the exponent for that value rather the specifying ack.ack_delay must be zero for those packets?
NAME This is true, there's no sense in defining an ackdelayexponent for Initial and Handshake packets if we're going to ignore the ACK delay anyway. Should be safe to recommend to just send a 0 for these packet number spaces. I updated the PR accordingly.

Since this now also touches the transport document, I guess we'll have to apply the late-stage consensus process to get this merged.
The main optimization the handshake timer makes is the assumption that maxackdelay does not need to be waited for before firing. However, it also uses a completely different equation for a timeout (2 SRTT vs SRTT + 4RTTVar). We could fix the maxackdelay difference by defaulting maxackdelay to 0(), like almost all other transport parameters. If there are no RTT measurements or estimates, we could use 1 second. If there are no RTT measurements, but there is an estimate, we could either use the PTO formula and assume RTTVar is 1/2 RTT(=> 3*RTT), or we could recommend estimating RTTVar as well as RTT. The first approach seems more practical. Another notable difference is the advice to retransmit all the handshake packets instead of 1 or 2, but given the current 3x amplification limit, if a server sends 2 packets in response to a ClientHello, they can't even retransmit both packets, so advising that they retransmit all handshake packets is not indicative of real-world behavior. If the server only has 1 handshake packet, then there's no change. The client should always be able to fit its CRYPTO data into a single packet, unless there are large client certs. If there are large client certs, one would expect time or packet threshold loss recovery to be faster and more effective than timer based retransmissions. And at that point, the client should have at least one RTT sample. The goal of this issue is to make the recovery mechanisms simpler, as well as including RTTVar in the handshake timer, as suggests.
Yes -- I was heading in this direction with , and it is how we're implementing recovery in quicly. I realized that we have a false separation between the crypto retransmission timer and the PTO timers. Using only the PTO timer basically is the most sensible approach. We need to ensure that maxackdelay is used only after handshake, and there's some care required there, but that's still much better than what we have now.
The maxackdelay is advertised in the transport parameters.

The recovery text assumes that this value is available right from the beginning of a connection.
I thought this sentence indicated it was 25ms until a value is received: "The maximum ack delay is communicated in the "maxackdelay" transport parameter and the default value is 25ms.", but I agree it could be clearer, ie: "and the default value and the value prior to receiving the transport parameters is 25ms."? As a related point, I think it turns out the maxackdelay doesn't come into play until the transport params are available, because "crypto packets SHOULD use a very short ack delay, such as the local timer granularity." URL
It's not used for sending, but we're using it when calculating the RTT.
Hmm, maybe we should default it to 0 before it's been received then? Or should we just specify it's 25ms until transport params have been received?
I'd argue that we should use 0 until receiving TP. We require endpoints to send ACKs for crypto packets immediately. That means that the ack-delay value found in the ACK packet is something that the peer could not control. It is my understanding that we consider these uncontrollable delays induced within an endpoint as part of RTT.
NAME : It's not about the RTT, it's about the PTO, or crypto timeout to be more precise. It's reasonable to continue using maxackdelay for RTT computations, since it caps ackdelay (ackdelay should be 0 or something very small for those anyways). But when computing the crypto timeout, we don't want to include the maxackdelay for the reasons you cite. The draft currently does not have the maxackdelay being used for the crypto retransmission timer, which was an oversight. We'll clean that up separately, but fortuitously, this means that there's no maxackdelay in the pseudocode or text to change. I don't mind initializing it to 0 or any value, but it won't have any real effect on endpoint behavior based on the draft. maxack_delay doesn't kick in until after the handshake is roughly complete.

The crypto retransmission timer doesn't use maxackdelay intentionally, see: URL "In order to quickly complete the handshake and avoid spurious retransmissions due to crypto retransmission timeouts, crypto packets SHOULD use a very short ack delay, such as the local timer granularity. ACK frames SHOULD be sent immediately when the crypto stack indicates all data for that packet number space has been received.
Same applies to
NAME Which why the spec says the following:
NAME the PR for this changed the transport doc. Can you check whether we need to run a consensus call?
The PR is already merged, so closing.
Still LGTM.