Change:
Initial packets and Handshake packets could be never acknowledged, but they are removed from bytes in flight when the Initial and <del> Handshake keys are discarded. </del> <ins> Handshake keys are discarded.  When Initial or Handshake keys are discarded, the PTO and loss detection timers MUST be reset, because discarding keys indicates forward progress and the loss detection timer may have been set for a now discarded packet number space. </ins> 5.3.1.

Discussion:
Pseudocode added, PTAL
I'm fine with requiring it, given it's already a design issue.
should be reset to 0 when a packet number space is dropped. I'd argue that this is the consistent thing to do, because when we drop a packet number space, we implicitely acknowledge all outstanding packets in that space (and remove them from ).
I think this is alright. It should happen anyway, since receiving an ACK should be the common case.
I also tend to think this is Ok. Importantly, if you don't get any ACKs, you also have no RTT samples, and in that case, continuing to backoff the PTO is very possibly the right thing to do.
Maybe I'm confused, but shouldn't be per-PN-space, now that PTO is per-PN-space ()?
I believe the simplest way to ensure QUIC isn't overly aggressive during the handshake and to encourage packet coalescing is to specify ptocount on a connection scope, similar to the rtt variables. I considered making ptocount per-PN space, but that doesn't ensure quite the same exponential backoff properties and I don't believe it's necessary.
I think we agree that PTO during handshake should be as aggressive as after the handshake. However, I am starting to wonder if the current spec. actually works that way. Consider the case when the server responds to ClientHello. It would be sending Initial, Handshake, and 1-RTT packet at the same time. Then, when those QUIC packets gets lost, the loss timer would be invoked three times, resulting in ptocount set to 3. Is that the intended behavior? I think in such case, ptocount should become one, after the PTO timers of all those epochs are triggered, once each. Therefore, to me, the correct logic seems to be: have ptocount for each epoch every time the per-epoch PTO timer is triggered, increment the per-epoch ptocount by 1 when an ACK is being received on any* epoch, reset pto_count of all the epochs PS. I acknowledge that the issue I'm discussing in this comment might be orthogonal to the original issue, and that it might deserve a separate issue.
NAME you make a good point.

I don't think this is orthogonal to the original issue, I think it's very much related. In addition to what you note, you would also need to use the per-epoch counter for determining how long to set the timer. This is going to be imperfect or ugly or both. If we use a single ptocount, we'll have duplicate counts. If we use separate ptocounts, we'll have to reconcile different epochs having varying counts. I think the behavior we're looking for is (i) use a separate ptocount per epoch, (ii) use the max of all ptocounts when setting the timer for any PN space, (iii) reset all pto_counts when an ACK is received for any epoch. This isn't great, and it is imperfect -- you can end up being more aggressive than with a single count. But I think it's good enough.
NAME The logic you describe sounds fine to me (apparently I missed (ii)), it would make the PTO behavior during handshake as aggressive as after the handshake. I cannot see when it would be more aggressive than that, and I think it's better than "imperfect but good enough."
NAME : In theory, if we use the max of counts when setting the timer, it is possible for a single pto_count to increase without increasing the max. Which means that the sender can effectively seem to not back off sometimes, causing it to be potentially more aggressive than after the handshake. I might have been a bit harsh earlier -- I think this is fine.
My plan is: 1) Keep a single ptocount. 2) Reset it when a packet number space is dropped, since that is an indication of forward progress. 3) Re-arm the loss detection timer when dropping a packet number space in case it was armed for the space being dropped. 4) Add some more explanatory text about how ptocount and multiple packet number spaces interact.
Discussed in ZRH. Proposed resolution is in , which should include corresponding updates to the pseudocode.