Change:
Strategies and implications of the frequency of generating acknowledgments are discussed in more detail in QUIC-RECOVERY. <ins> 13.1.2. </ins> To limit ACK Ranges (see ack-ranges) to those that have not yet been received by the sender, the receiver SHOULD track which ACK frames have been acknowledged by its peer.  The receiver SHOULD exclude already acknowledged packets from future ACK frames whenever these <del> packets would unnecessarily contribute to the ACK frame size. Because ACK frames are not sent in response to ACK-only packets, a receiver that is only sending ACK frames will only receive acknowledgements for its packets if the sender includes them in packets with non-ACK frames.  A sender SHOULD bundle ACK frames with other frames when possible. </del> <ins> packets would unnecessarily contribute to the ACK frame size.  When the receiver is only sending non-ACK-eliciting packets, it can bundle a PING or other small ACK-eliciting frame with a fraction of them, such as once per round trip, to enable dropping unnecessary ACK ranges and any state for previously sent packets.  The receiver MUST NOT bundle an ACK-elicing frame, such as a PING, with all packets that would otherwise be non-ACK-eliciting, in order to avoid an infinite feedback loop of acknowledgements. </ins> To limit receiver state or the size of ACK frames, a receiver MAY limit the number of ACK Ranges it sends.  A receiver can do this even

Discussion:
MUST NOT bundle a PING with all packets that would otherwise be ACK-only. If there's anything else discussed in London that I missed, please tell me.
Isn't this just moving up one level in the inception layer? Now you must not send ACK+PING too often to prevent an indefinite feedback loop? Why not just say that an ACK should not ACK / PAD only frames for more than a fraction of the packets to avoid feedback loops and to ensure eventual reduction of gap accounting?
NAME My past experience has been that it's better if the sender of ACKs is in control of how often they want an ACK in response. There are a number of packet tracking/ACKing algorithms which never require ACKs of ACK-only packets, and I think we should accommodate those. Making the receiver of ACKs guess how often to ACK ACKs is a problem that's impossible to get right, and as NAME said on the issue, one can never rely on any receiver behavior regarding when they'll ACK ACKs, so it's more robust if the sender is in control. I will add normative text about not including a PING with every ACK.
OK, that makes sense.
I've now removed ACK-only from the transport text, and replaced it with ACK-eliciting.
The transport spec says in section 13.1.1: "An endpoint MUST NOT send a packet containing only an ACK frame in response to a packet containing only ACK or PADDING frames, even if there are packet gaps which precede the received packet. This prevents an indefinite feedback loop of ACKs." I argue that this MUST NOT should be changed to SHOULD NOT. Fist, the infinite feedback can be prevented if, for example, an implementation only sends an ACK for N packets received, so there is really no need to be that strict. Second, ACK of ACK are generally useful. They enable trimming the grow of ACK lists in a controlled way. In fact, I found that problem in interop tests. Some implementations would send thousands of data packets without sending a single ACK of ACK. That means the sender is stuck with a large ACK dashboard. Yes, it could be trimmed with timers, but that's hardly a controlled process. I fixed this by sending an ACK + PING packet whenever there the unacked ACK list is too long, but that's a hack.

I'd argue that ACK+PING isn't a hack, but instead a simple way for the sender, whose state we're trying to limit, to balance the amount of state it stores vs the extra ACKs being received. Getting the peer to implement the correct ACK behavior by sending a single extra byte is much simpler and more robust in my experience than relying on the receiver to implement an "ACK every 10/20/etc ACKs" policy in a way that every sender is happy with. This could likely use more text and there's still an outstanding editorial issue to move most of the ACK sending text that's in recovery into transport, so it's all in one place, since I believe there are currently a few subtle inconsistencies.
Completely agree. Ian hits on the key point here. In the case of an endpoint that would like to limit the amount of state it stores, it's highly desirable for THAT endpoint to be in control. ACK+PING, satisfies that. Relying on ACKs of ACKs from the peer does not, sadly.
Agreed with NAME Irrespective of what we recommend here, note that a sender of ACKs cannot assume what the peer will do -- when the peer will send an ACK for ACKs, I mean -- so, it will end up having to send a periodic PING anyways. Piggybacking a PING periodically (once an RTT, for example) is useful for RTT measurement as well, since ACK of ACKs do not get used for RTT (see for more discussion on this point).
An alternative would be allowing sending ACKs-of-ACKs, if you are sending non-(ACK|PADDING) frames. So, maybe: "An endpoint MUST NOT send a packet containing only ACK or PADDING frames in response to a packet containing only ACK or PADDING frames, if the previous packet it sent contained only ACK or PADDING frames."
As discussed in London, NAME to write a PR with some advisory text
So many comments, so much opportunity for this to get worse if we don't stop.Minor nit, but looks good.Text looks good, just noticed a few minor whitespace nits while reading through.