Change:
5. An endpoint can send multiple ACK_FREQUENCY frames, and each one of <del> them can have different values.  An endpoint MUST use a sequence number of 0 for the first ACK_FREQUENCY frame it constructs and sends, and a strictly increasing value thereafter. </del> <ins> them can have different values in all fields.  An endpoint MUST use a sequence number of 0 for the first ACK_FREQUENCY frame it constructs and sends, and a strictly increasing value thereafter. </ins> An endpoint MUST allow reordered ACK_FREQUENCY frames to be received and processed, see Section 13.3 of QUIC-TRANSPORT.

Discussion:
Maybe it would be more consistent if this was a field on the ACK_FREQUENCY frame?
I agree. Not only for consistency but also for practical benefits. Firstly, in many cases, the sender will only be able to tell if the path is going to have lots of reorders. Allowing the sender to alter the client behavior mid-connection would be beneficial, as that would allow the sender reduce the ACK rate when it disables packet number-based loss detection. The second use case is for clustered servers sending different streams from different hosts. Packets being sent from such clustered servers would have reorder when there are multiple servers handling streams, but not when there is only server handling streams (consider the case where only one stream, or only one HTTP request is open). In such deployments, it is beneficial to have the capability of turning off reordering detection mid-connection.
Let's assume here that peers might adjust their reordering threshold based on the amount of reordering they're seeing, i.e. that they will increase it from the default value of 3 to a higher value if they detect a lot of spurious retransmissions when using 3. In that case, would it maybe make sense to define a threshold when to send an ACK for a reordered packet? For example, let's say packet N is missing, but N+1 is received. If you're using a high reordering threshold, you wouldn't care to receive an ACK for this event immediately. However, you'd still care to get an ACK when N+10 is received, because in that case your packet number-based loss detection will be able to quickly repair the loss of packet N.
NAME I agree that that's a possibility. At the same time, it could be well the case that simply turning off reordering detection and solely relying on the time-based loss recovery would be sufficient.
NAME I can't really tell what makes sense from the point of a congestion control algorithm, but I'm wondering if it makes sense to specify something here that would allow a wide range of algorithms to get the kind of information that they deem useful. If we made that field a varint instead of a bool (then we can also avoid the question of how we would encode a bool), you could still effectively disable ACKs for reordered packets by sending a very large value for that field, if you want to disable packet number-based loss recovery.

When NAME and I were discussing this, we thought it was best to not make this part of the mechanism overly complex, hence the transport param. Unfortunately, we have very little(or no) deployment experience in this area, so the TP was more of a future-proofing mechanism than one based on past experience. If we were going to add a field, I'd suggest a max_reordering field where 0 indicates any reordering is tolerated and any other values indicate a max packet number gap before an immediate ACK is sent? If you want immediate ACK upon reordering, you'd send 1. That only adds a byte to the frame size in almost all cases, but I think should work well in a wide variety of use cases. My main concern is whether the implementation complexity increases more than the value it's providing?
I think there's value in making this a field in the frame instead of a TP... as NAME noted, we used a TP because that seemed like the simplest approach, not necessarily the most flexible one. I agree with NAME that allowing for communicating a "threshold" has the most room for play with reordering robustness in the future. I'm not convinced that it'll get all that used, but if the receiver behavior is not much more complicated to implement, then I'm ok with specifying that. So, here's a shot at defining receiver behavior. A receiver has to measure the degree of reordering and then decide whether to ack immediately or not. This degree of reordering can be defined as follows: the distance of the received packet from the largestreceived (for that PN space). Basically: A couple of examples to see if this works out. Let's say LR is the largestreceived packet number. A reordering distance of 2 means that LR+2 and larger or LR-2 and smaller will trigger an immediate ack. This seems ok. All distances greater than 2 also seem ok. Reordering distance of 1 is a bit tricky. This distance means that if LR+1 is received, that triggers an immediate ack. Similarly, anything smaller than or equal to LR-1 will also trigger immediate ack (anything smaller than the largest received). The current reordering recommendation in the transport draft will have the receiver acking immediately on receiving LR-1, and we should be able to cover that case, so we should be able to express this value.

But this is a bit wonky, since LR+1 is basically the next expected, and this reordering value effectively turns into . It would be nice to avoid this problem. We can do that by using Ian's suggestion of special casing the value 1: "any reordering, as defined as a PN that does not increase the LR by 1, will trigger an ack." Similarly, special casing the value 0 for disable immediate acking on reordering is useful. Having worked through this, it doesn't seem that terrible. I'm ok with varint or single byte. I agree with NAME that the most usefulness will be in 1 byte, but I can see the value in leaving it open and uniform. Thoughts?
So the final algorithm becomes:
I'd rather have a varint for consistency, even if it's almost always a single byte.
NAME thank you for picking up my suggestion and writing the pseudo code. I'm not sure if just looking at the largest received is sufficient to properly cover all cases. Assume you receive packet , packet . At this point . Now you receive . I would have assumed that it makes sense now to send an immediate ACK to help with the recovery of , however, the algorithm doesn't capture that case. Furthermore, I was wondering about the negative branch (where ). This branch can only be taken if we sent an ACK earlier for exceeding the . Assuming that ACK was received, the packet in question would already have been declared lost, so in that case sending an immediate ACK wouldn't make any difference. Is my understanding correct that the negative branch exists for the case in which the original ACK was lost? Encoding-wise, we might be able to simplify things a bit replacing by (where a of 1 would be a of 2). Then we could avoid special-casing the value of 1. I'm also wondering how many immediate ACKs you're supposed to send. Currently, the draft has some quite complicated conditions for this: Do we need some similar advice here? Or do we need to make it configurable?
NAME on the point about how many immediate ACKs to send, I believe we should only send one, so I have an issue() and PR() to change the text you quoted.

In terms of the 'negative branch' as you're describing it, the idea is that it's very possible the packet has not yet been declared lost yet, even though the ACK has arrived. If they're using this reordering tolerant setting, it seems likely they're tolerant to more reordering than a typical sender. For example, it could be because they have adaptive packet threshold loss detection and the threshold has been increased substantially due to observing past reordering.
We definitely need to have a few people ship this reordering tolerant feature before we finalize this draft. I'm quite confident in everything else in the draft, but I'm fairly unsure about exactly how this can and should be used. I'm also not yet sure packet threshold is actually better than time. It seems more appealing, but I think it depends on the use case. I'm also concerned it adds non-trivial implementation complexity. Implementations already have a maxackdelay and a number of packets before sending an immediate ACK, so this is just adding a mechanism to change those thresholds during the connection. However, this reordering feature may end up substantially changing the code to send ACKs. I'd be pretty sad if a bunch of implementations didn't implement the draft because they didn't want to deal with the extra complexity.
I agree, NAME which is why I wanted to go through and see if we could define simple enough behavior that is useful. I don't think we want to be perfect with the detection, but reasonable. I'll think of simplifications to this, but we want to make sure that we dont make this unnecessarily ornate. I am concerned that this threshold becomes another footgun, since we really don't have a good recommendation for how to set it. The primary property we want is a dynamic way to indicate to the peer to not send immediate acks on reordering. Simply moving the TP to the frame will give us that. I am increasingly leaning towards just calling this a boolean instead of a threshold. I will plan to write that up by tomorrow. Any strong objections?
Boolean as a frame field works perfectly fine for my use case.
I prefer "Ingnore Reordering" to "Ignore Order", though I admit the latter is slightly shorter. One suggestion on making the text slightly more proscriptive.