Change:
independent of whether it also sends the min_ack_delay transport parameter or not. <ins> Endpoints MUST NOT remember the value of the min_ack_delay transport parameter they received.  Consequently, ACK_FREQUENCY frames cannot be sent in 0-RTT packets, as per Section 7.4.1 of QUIC-TRANSPORT. </ins> This Transport Parameter is encoded as per Section 18 of QUIC- TRANSPORT.

Discussion:
and And by implication, cannot send ACK_FREQUENCY in 0-RTT packets.
The transport I-D 31 : This information is missing from .
FWIW, I tend to think that this issue is coupled with , and that endpoints do not need to, due to the reasons being explained on that issue.
Fixed by
See Table in of the transport draft.
We recommend endpoints to ACK Initial and Handshake packets immediately (see URL). I do not think we need to change that, and therefore my view is that use of ACK_FREQUENCY frames can (and should) be limited to 1-RTT.
Agreed, I think we just need to specify that.
Just a note that, new TPs are required to clarify if the TP is to be remembered (URL). Based on the understanding that the use of the ACKFREQUENCY frame will be limited to 1-RTT packets, I assume that remembering the minack_delay TP will be prohibited.
Good point NAME I do not believe minackdelay should be remembered, since it has no use prior to handshake completion.
I agree that ACKFREQUENCY should not apply to Initial and Handshake packets. That doesn't mean that we need to limit ACKFREQUENCY to 1-RTT packets though, it could apply to 0-RTT packets as well, if peers are required to remember the value of the TP. The client could then send an ACK_FREQUENCY in 0-RTT. I don't have a strong preference in either direction, but preventing a flood of ACKs for 0-RTT packets sounds like it could potentially be useful.
Considering our track record of allowing most frames to be sent in 0-RTT, I am fine with allowing the transmission of ACKFREQUENCY frames in 0-RTT. OTOH, I do not think we should require endpoints to retain minackdelay TP across resumptions. That would essentially prohibits client from sending ACKFREQUENCY frames in 0-RTT.
NAME Your two statements seem to contradict each other. If we allow ACKFREQUENCY in 0-RTT, peers need to remember the value of the TP. If peers are not required to remember the value of the TP, ACKFREQUENCY can't be sent in 0-RTT, otherwise a client would risk a PROTOCOL_VIOLATION if a server disabled the extension.

NAME That's a good point. And as you might have already observed, even if the client remembered minackdelay, it might still not be possible to send an ACKFREQUENCY frame in 0-RTT. That's because maxackdelay would be unknown. I think we are reaching consensus that clients would not send ACKFREQUENCY frames in 0-RTT, even if the specification allowed that?
Now I'm a bit confused. In my mind, this is how this extension works (describing it using "client" and "server" for added clarity, it works the same way in the opposite direction): The client declares a maxackdelay in the transport parameters. When generating acknowledgements, the server will then make sure that every ACK is generated within that time frame. When the client sends an ACKFREQUENCY frame, it instructs the server to discard the previous maxackdelay value and use the one encoded in the frame instead. Assuming that my understanding is correct, the fact that the client hasn't received the server's maxackdelay should be irrelevant when considering whether we want to send this frame in 0-RTT packets. Furthermore, the fact that the ClientHello has to be received before the server can decode any 0-RTT packet would guarantee that the server has processed the client's transport parameters before it is able to process any ACKFREQUENCY frame.
NAME and I chatted about this; summarizing. An endpoint's ACKFREQUENCYFRAME updates the received maxackdelay. This makes all situations where an endpoint sends an ACKFREQUENCYFRAME without receiving the peer's maxackdelay problematic. Since a client does not remember the peer's maxackdelay, sending an ACKFREQUENCYFRAME that updates it makes little sense. We should disallow ACKFREQUENCYFRAMEs in 0-RTT packets because a client does not have the base value which it wants to update with this frame until 1-RTT keys are established.
And we agree with NAME that is intertwined with this issue, since if the transport parameter is not remembered, you can't send the ACK_FREQUENCY frame.
My preference here is "application" packet number space. This means that the transport parameter needs to be remembered.

It also means that - because maxackdelay is not remembered - that you have to avoid exceeding the maxackdelay default (and permit that variance as a server if you set a lower value for maxackdelay).
My real issue is whether the frames might appear before the TP negotiation has concluded. The client should not send ACK FREQUENCY frames before that. I think this naturally precludes sending ACK FREQUENCY in 0-RTT, but there might be corner cases in which the client knows the result of the TP negotiation before it has access to the 1-RTT keys -- for example if some of the crypto processing is going on in a crypto offload engine. If we are firm on negotiation, then we don't need to make a statement about 0RTT vs 1RTT.
NAME I'm not sure if that follows the design of RFC 9000. For frames that can be sent in 0-RTT, RFC 9000 requires endpoints to remember and reuse the value of the Transport Parameters:
Another potential option here in support of the basic design: this document could require that the value of maxackdelay be remembered alongside minackdelay, (only)? for the generation of ACK_FREQUENCY frames.
NAME Would you mind elaborate why your implementation cannot prohibit frames being sent in 0-RTT packets from being affected by TPs other than remembered ones? RFC 9000 states that when sending frames in 0-RTT packets, a client MUST only use remembered transport parameters, and that the definition of a new transport parameter MUST specify whether storing the transport parameter for 0-RTT is mandatory, optional, or prohibited (). So it seems to me that, for Transport parameters that are prohibited to be remembered, QUIC stacks are expected to be capable of prohibiting those parameters to be used when sending frames using 0-RTT packets. It seems to me that you are against us building extensions on that guidance.
I think there is broad support for not sending ACK_FREQUENCY frames before the negotiation completes. In response to the comment from NAME this requires that "storing the transport parameter for 0-RTT is prohibited."

If we do that, we also satisfy the requirement stated by NAME that 0-RTT processing be pretty much the same as 1-RTT processing: there is no new difference between 0-RTT and 1-RTT, in both cases the transport can only send the frame if the peer has explicitly accepted them.
Thanks NAME and NAME I agree that if we prohibit storing minackdelay, ACKFREQUENCY can't be sent in 0-RTT, and I believe that should solve NAME issue? Storing BOTH minackdelay and maxack_delay is a direction I'd really rather avoid.
This works to ensure that there are no surprises for servers. But it doesn't prevent clients from sending the frame in 0-RTT. Our stack will apply transport parameters after receiving them. This is before handshake completion, so if we are still sending 0-RTT, we might send the frame. I don't believe that we will in practice, due to the logic we use for sending it. That logic is something that might change, so there are no strong guarantees. I do think that this is a good solution, I just want to make the consequences clear.
NAME If we are to prohibit minackdelay from being remembered, I do not think we can allow them to be sent in 0-RTT. Requoting from RFC 9000, when sending frames in 0-RTT packets, a client MUST only use remembered transport parameters, and that the definition of a new transport parameter MUST specify whether storing the transport parameter for 0-RTT is mandatory, optional, or prohibited (). Am I missing something? Also, I would point out that, even for remembered TPs, QUIC stacks are required to refrain from using the newly received ones in 0-RTT packets. For example, if the remembered value of MAXSTREAMS is 0 and the newly received value is 4, an endpoint is forbidden to open any stream in 0-RTT even after receiving the transport parameters. It is only when you switch to using 1-RTT packets that the newly received transport parameter is applied. For your implementation, wouldn't it be possible to use the same latch for ackfrequency?
Oh, whoops. We don't have that latch.

We'll probably open 4 streams if initialmaxstreams_xxx is 4 in the handshake and we remembered 0. In any case, we can probably add a latch. It might even make the code simpler.
Thank you for the PR. Looks good, below is nothing more than an editorial URL of suggestions, but lgtm