a packet.  Restarting this timer when sending a packet ensures that connections are not closed after new activity is initiated.  An endpoint might need to send ack-eliciting packets to avoid an idle timeout if it is expecting response data, but does not have or is unable to send application data. <del> An endpoint that sends packets close to the effective timeout risks having them be discarded at the peer, since the peer might enter its draining state before these packets arrive.  An endpoint can send a PING or another ack-eliciting frame to test the connection for liveness if the peer could time out soon, such as within a PTO; see Section 6.2 of QUIC-RECOVERY.  This is especially useful if any available application data cannot be safely retried.  Note that the application determines what data is safe to retry. </del>  10.3. The PING frame can be used to keep a connection alive when an application or application protocol wishes to prevent the connection <del> from timing out.  An application protocol SHOULD provide guidance about the conditions under which generating a PING is recommended. This guidance SHOULD indicate whether it is the client or the server that is expected to send the PING.  Having both endpoints send PING frames without coordination can produce an excessive number of packets and poor performance. A connection will time out if no packets are sent or received for a period longer than the time negotiated using the max_idle_timeout transport parameter; see termination.  However, state in middleboxes might time out earlier than that.  Though REQ-5 in RFC4787 recommends a 2 minute timeout interval, experience shows that sending packets every 15 to 30 seconds is necessary to prevent the majority of middleboxes from losing state for UDP flows. </del>  19.3. HTTP clients are expected to request that the transport keep connections open while there are responses outstanding for requests <del> or server pushes, as described in Section 19.2 of QUIC-TRANSPORT.  If the client is not expecting a response from the server, allowing an idle connection to time out is preferred over expending effort </del>  maintaining a connection that might not be needed.  A gateway MAY maintain connections in anticipation of need rather than incur the latency cost of connection establishment to servers.  Servers SHOULD

This moves it up under the idle timeout section. As discussed on the issue, the HTTP draft is basically good.
The transport Draft states: This guidance was added to the HTTP Draft in , but was subsequently removed.
I guess that something to discuss in the applicability draft as well
Looks like made this text more generic, leaving the specifics of how to keep a connection alive (e.g. with PING frames) to the transport implementation. The text in question is now in Section 5.1: It's possible the transport draft needs a similar generalization, to recommend implementations expose a way for the application layer to control whether an connection is idle.
Actually there is a section on "Session resumption versus Keep-alive" in the applicability draft already. Do we need to say more? Is that needed in the transport draft as well?
On the whole, this is good. Might be worth having something a little stronger than "might provide"; that would be normative, but the old text already hinted fairly strongly that this was a capability that needed to be exposed to applications.

a packet.  Restarting this timer when sending a packet ensures that connections are not closed after new activity is initiated. <ins> 10.2.1. An endpoint that sends packets close to the effective timeout risks having them be discarded at the peer, since the peer might enter its draining state before these packets arrive. An endpoint can send a PING or another ack-eliciting frame to test the connection for liveness if the peer could time out soon, such as within a PTO; see Section 6.2 of QUIC-RECOVERY.  This is especially useful if any available application data cannot be safely retried. Note that the application determines what data is safe to retry. 10.2.2. </ins> An endpoint might need to send ack-eliciting packets to avoid an idle timeout if it is expecting response data, but does not have or is unable to send application data.  <ins> An implementation of QUIC might provide applications with an option to defer an idle timeout.  This facility could be used when the application wishes to avoid losing state that has been associated with an open connection, but does not expect to exchange application data for some time.  With this option, an endpoint could send a PING frame periodically to defer an idle timeout; see frame-ping. Application protocols that use QUIC SHOULD provide guidance on when deferring an idle timeout is appropriate.  Unnecessary sending of PING frames could have a detrimental effect on performance. A connection will time out if no packets are sent or received for a period longer than the time negotiated using the max_idle_timeout transport parameter; see termination.  However, state in middleboxes might time out earlier than that.  Though REQ-5 in RFC4787 recommends a 2 minute timeout interval, experience shows that sending packets every 15 to 30 seconds is necessary to prevent the majority of middleboxes from losing state for UDP flows. </ins> 10.3. The PING frame can be used to keep a connection alive when an application or application protocol wishes to prevent the connection  <ins> from timing out; see defer-idle. </ins> 19.3. HTTP clients are expected to request that the transport keep connections open while there are responses outstanding for requests  <ins> or server pushes, as described in Section 10.2.2 of QUIC-TRANSPORT. If the client is not expecting a response from the server, allowing an idle connection to time out is preferred over expending effort </ins> maintaining a connection that might not be needed.  A gateway MAY maintain connections in anticipation of need rather than incur the latency cost of connection establishment to servers.  Servers SHOULD


packets larger than the smallest allowed maximum packet size of 1200 bytes.  A client MUST expand the payload of all UDP datagrams carrying Initial packets to at least the smallest allowed maximum packet size (1200 bytes) by adding PADDING frames to the Initial packet or by client believes that the network path and peer both support the size that it chooses. <del> UDP datagrams MUST NOT be fragmented at the IP layer.  In IPv4 IPv4, the DF bit MUST be set to prevent fragmentation on the path. </del> A server MUST discard an Initial packet that is carried in a UDP datagram with a payload that is less than the smallest allowed maximum packet size of 1200 bytes.  A server MAY also immediately The server MUST also limit the number of bytes it sends before validating the address of the client; see address-validation. <del> 14.1. </del>  The Path Maximum Transmission Unit (PMTU) is the maximum size of the entire IP packet including the IP header, UDP header, and UDP maximum packet size to allow for unknown tunnel overheads or IP header options/extensions. <del> 14.1.1. </del>  Path Maximum Transmission Unit Discovery (PMTUD; RFC1191, RFC8201) relies on reception of ICMP messages (e.g., IPv6 Packet Too Big QUIC's loss detection algorithm determines that the quoted packet has actually been lost. <del> 14.2. </del>  Datagram Packetization Layer PMTU Discovery (DPLPMTUD; DPLPMTUD) relies on tracking loss or acknowledgment of QUIC packets that are QUIC endpoints implementing DPLPMTUD maintain a maximum packet size (DPLPMTUD MPS) for each combination of local and remote IP addresses. <del> 14.2.1. </del>  From the perspective of DPLPMTUD, QUIC transport is an acknowledged packetization layer (PL).  A sender can therefore enter the DPLPMTUD BASE state when the QUIC connection handshake has been completed. <del> 14.2.2. </del>  QUIC provides an acknowledged PL, therefore a sender does not implement the DPLPMTUD CONFIRMATION_TIMER while in the SEARCH_COMPLETE state; see Section 5.2 of DPLPMTUD. <del> 14.2.3. </del>  An endpoint using DPLPMTUD requires the validation of any received ICMP Packet Too Big (PTB) message before using the PTB information, The considerations for processing ICMP messages described in pmtud also apply if these messages are used by DPLPMTUD. <del> 14.3. </del>  PMTU probes are ack-eliciting packets. consume congestion window, which could delay subsequent transmission by an application. <del> 14.3.1. </del>  Endpoints that rely on the destination connection ID for routing incoming QUIC packets are likely to require that the connection ID be

This was mixed in with other packet size text. A clean split is possible. (Note that this might rot with all the other changes that are in flight. This is a straight move, so it can be rebased easy on that basis.)

packets larger than the smallest allowed maximum packet size of 1200 bytes. <ins> UDP datagrams MUST NOT be fragmented at the IP layer.  In IPv4 IPv4, the DF bit MUST be set to prevent fragmentation on the path. 14.1. </ins> A client MUST expand the payload of all UDP datagrams carrying Initial packets to at least the smallest allowed maximum packet size (1200 bytes) by adding PADDING frames to the Initial packet or by client believes that the network path and peer both support the size that it chooses.  A server MUST discard an Initial packet that is carried in a UDP datagram with a payload that is less than the smallest allowed maximum packet size of 1200 bytes.  A server MAY also immediately The server MUST also limit the number of bytes it sends before validating the address of the client; see address-validation.  <ins> 14.2. </ins> The Path Maximum Transmission Unit (PMTU) is the maximum size of the entire IP packet including the IP header, UDP header, and UDP maximum packet size to allow for unknown tunnel overheads or IP header options/extensions.  <ins> 14.2.1. </ins> Path Maximum Transmission Unit Discovery (PMTUD; RFC1191, RFC8201) relies on reception of ICMP messages (e.g., IPv6 Packet Too Big QUIC's loss detection algorithm determines that the quoted packet has actually been lost.  <ins> 14.3. </ins> Datagram Packetization Layer PMTU Discovery (DPLPMTUD; DPLPMTUD) relies on tracking loss or acknowledgment of QUIC packets that are QUIC endpoints implementing DPLPMTUD maintain a maximum packet size (DPLPMTUD MPS) for each combination of local and remote IP addresses.  <ins> 14.3.1. </ins> From the perspective of DPLPMTUD, QUIC transport is an acknowledged packetization layer (PL).  A sender can therefore enter the DPLPMTUD BASE state when the QUIC connection handshake has been completed.  <ins> 14.3.2. </ins> QUIC provides an acknowledged PL, therefore a sender does not implement the DPLPMTUD CONFIRMATION_TIMER while in the SEARCH_COMPLETE state; see Section 5.2 of DPLPMTUD.  <ins> 14.3.3. </ins> An endpoint using DPLPMTUD requires the validation of any received ICMP Packet Too Big (PTB) message before using the PTB information, The considerations for processing ICMP messages described in pmtud also apply if these messages are used by DPLPMTUD.  <ins> 14.4. </ins> PMTU probes are ack-eliciting packets. consume congestion window, which could delay subsequent transmission by an application.  <ins> 14.4.1. </ins> Endpoints that rely on the destination connection ID for routing incoming QUIC packets are likely to require that the connection ID be


read the ECN codepoints from the enclosing IP packet, which is not possible on all platforms. <del> A packet detected by a receiver as a duplicate does not affect the receiver's local ECN codepoint counts; see (security-ecn) for relevant security concerns. </del>  If an endpoint receives a QUIC packet without an ECT or CE codepoint in the IP packet header, it responds per generating-acks with an ACK codepoints, it does not increase ECN counts. Coalesced packets (see packet-coalesce) mean that several packets can <del> share the same IP header.  The ECN counter for the ECN codepoint </del>  received in the associated IP header are incremented once for each QUIC packet, not per enclosing IP packet or UDP datagram. codepoint for only the first ten outgoing packets on a path, or for a period of three RTTs, whichever occurs first. <del> Implementations MAY experiment with and use other strategies for use of ECN.  Other methods of probing paths for ECN support are possible, as are different marking strategies.  Implementations can also use the ECT(1) codepoint, as specified in RFC8311. </del>  13.4.2.2.

Taking Gorry's suggestions, which seem quite reasonable.
(1) NiT: /The ECN counter for the ECN codepoint received in the associated IP header are incremented once for each QUIC packet, not per enclosing IP packet or UDP datagram./ mixed singular and plural - is this /counters/? (2) I like this phrase in the security considerations also from the point of view of how to generate transport feedback for ECT(?). Can we call this out here: /QUIC endpoints ignore the ECN codepoint field on an IP packet unless at least one QUIC packet in that IP packet is successfully processed/ (3) General experiments are not permitted in RFC8311, only using experimental RFCs. I think therefore, we should be clear in the detail here: /Implementations MAY experiment with and use other strategies for use of ECN. Other methods of probing paths for ECN support are possible, as are different marking strategies. Implementations can also use the ECT(1) codepoint, as specified in {{?RFC8311}}./ I’d propose something more like this: /Other methods of probing paths for ECN support are possible, as are different marking strategies. Implementations MAY use other methods defined in RFCs, as specified in {{?RFC8311}}. Implementations that use the ECT(1) codepoint, need to perform ECN validation using this code point./

read the ECN codepoints from the enclosing IP packet, which is not possible on all platforms.  <ins> An IP packet that results in no QUIC packets being processed does not increase ECN counts.  A QUIC packet detected by a receiver as a duplicate does not affect the receiver's local ECN codepoint counts; see security-ecn for relevant security concerns. </ins> If an endpoint receives a QUIC packet without an ECT or CE codepoint in the IP packet header, it responds per generating-acks with an ACK codepoints, it does not increase ECN counts. Coalesced packets (see packet-coalesce) mean that several packets can  <ins> share the same IP header.  The ECN counts for the ECN codepoint </ins> received in the associated IP header are incremented once for each QUIC packet, not per enclosing IP packet or UDP datagram. codepoint for only the first ten outgoing packets on a path, or for a period of three RTTs, whichever occurs first.  <ins> Other methods of probing paths for ECN support are possible, as are different marking strategies.  Implementations MAY use other methods defined in RFCs; see RFC8311.  Implementations that use the ECT(1) codepoint need to perform ECN validation using ECT(1) counts. </ins> 13.4.2.2.


1-RTT (short-header) <del> A CONNECTION_CLOSE frame of type 0x1d cannot appear in Initial or Handshake packets. </del>  Section 4 of QUIC-TLS provides more detail about these restrictions. Note that all frames can appear in 1-RTT packets. format and assigned semantics of any fields in the frame. The initial contents of this registry are tabulated in frame-types.  22.4.

The first inverts the description of "ih" to be clearer. The second makes it clearer for IANA that the "packets" column can be ignored.

1-RTT (short-header)  <ins> Only a CONNECTION_CLOSE frame of type 0x1c can appear in Initial or Handshake packets. </ins> Section 4 of QUIC-TLS provides more detail about these restrictions. Note that all frames can appear in 1-RTT packets. format and assigned semantics of any fields in the frame. The initial contents of this registry are tabulated in frame-types. <ins> Note that the registry does not include the "Packets" column from frame-types. </ins> 22.4.


initial_max_stream_data_bidi_remote, or initial_max_streams_uni and initial_max_stream_data_uni.  A server MUST either reject 0-RTT data or abort a handshake if the implied values for transport parameters cannot be supported.

The section for "Values of Transport Parameters for 0-RTT" specifies which parameters a client MUST or MUST NOT remember. It does not do the same for a server. (It implies that ones a client MUST NOT remember also don't need to be remembered by a server, and it lists a subset of the remaining as ones the server MUST remember.) This commit adds the remaining parameters to a list that the server need not remember.
This still looks good with the latest commit Jana pushed.
The "Values of Transport Parameters for 0-RTT" section lists some, but not all, of the transport parameters defined in the spec. As currently written, it is ambiguous whether a server needs to remember the parameters not listed. (A list of parameters that the client MUST NOT remember, and therefore the server need not remember, is provided, as well as a list that the server MUST remember so it doesn't lower limits.) As far as I understand the definitions of the remaining parameters, there isn't any need for a server to remember them. However, instead of requiring implementors to read through all of the transport parameter definitions and infer this on their own, it would be easier on implementors to spell this out in this section. (This is required for definitions of new parameters.)
I like the latest text!

initial_max_stream_data_bidi_remote, or initial_max_streams_uni and initial_max_stream_data_uni. <ins> A server MAY store and recover the previously sent values of the max_idle_timout, max_udp_payload_size, and disable_active_migration parameters and reject 0-RTT if it selects smaller values.  Lowering the values of these parameters while also accepting 0-RTT data could degrade the performance of the connection.  Specifically, lowering the max_udp_payload_size could result in dropped packets leading to worse performance compared to rejecting 0-RTT data outright. </ins> A server MUST either reject 0-RTT data or abort a handshake if the implied values for transport parameters cannot be supported.


An HTTP origin advertises the availability of an equivalent HTTP/3 endpoint via the Alt-Svc HTTP response header field or the HTTP/2 <del> ALTSVC frame (ALTSVC), using the ALPN token defined in connection- establishment. </del>  For example, an origin could indicate in an HTTP response that HTTP/3 was available on UDP port 50781 at the same hostname by including the

Actually, as 3.1 is "to bre removed before publication", the expansion and ref should be in 3.2.1.

An HTTP origin advertises the availability of an equivalent HTTP/3 endpoint via the Alt-Svc HTTP response header field or the HTTP/2  <ins> ALTSVC frame (ALTSVC), using the Application Layer Protocol Negotiation (ALPN) RFC7301 token defined in connection-establishment. </ins> For example, an origin could indicate in an HTTP response that HTTP/3 was available on UDP port 50781 at the same hostname by including the


amount of data. Implementations MUST support buffering at least 4096 bytes of data <del> received in out of order CRYPTO frames.  Endpoints MAY choose to </del>  allow more data to be buffered during the handshake.  A larger limit during the handshake could allow for larger keys or credentials to be exchanged.  An endpoint's buffer size does not need to remain

NAME should merge this.
I'm assuming that you checked the others, and therefore surprised we got the others right.

amount of data. Implementations MUST support buffering at least 4096 bytes of data  <ins> received in out-of-order CRYPTO frames.  Endpoints MAY choose to </ins> allow more data to be buffered during the handshake.  A larger limit during the handshake could allow for larger keys or credentials to be exchanged.  An endpoint's buffer size does not need to remain


The size of the first packet sent by a client will determine whether a server sends a Version Negotiation packet.  Clients that support <del> multiple QUIC versions SHOULD pad the first packet they send to the largest of the minimum packet sizes across all versions they support. This ensures that the server responds if there is a mutually supported version. </del>  6.1. authenticated negotiation of an application protocol (TLS uses ALPN RFC7301 for this purpose) <del> An endpoint can verify support for Explicit Congestion Notification </del>  (ECN) in the first packets it sends, as described in ecn-validation. The CRYPTO frame can be sent in different packet number spaces endpoint SHOULD NOT coalesce multiple packets at the same encryption level. <del> Senders MUST NOT coalesce QUIC packets for different connections into a single UDP datagram.  Receivers SHOULD ignore any subsequent packets with a different Destination Connection ID than the first packet in the datagram. </del>  Every QUIC packet that is coalesced into a single UDP datagram is separate and complete.  The receiver of coalesced QUIC packets MUST The algorithms in QUIC-RECOVERY are expected to be resilient to receivers that do not follow guidance offered above.  However, an <del> implementer should only deviate from these requirements after careful consideration of the performance implications of doing so. </del>  An endpoint that is only sending ACK frames will not receive acknowledgments from its peer unless those acknowledgements are frame to become too large.  A receiver can discard unacknowledged ACK Ranges to limit ACK frame size, at the cost of increased retransmissions from the sender.  This is necessary if an ACK frame <del> would be too large to fit in a packet, however receivers MAY also limit ACK frame size further to preserve space for other frames. </del>  A receiver MUST retain an ACK Range unless it can ensure that it will not subsequently accept packets with numbers in that range. bundle a PING or other small ack-eliciting frame occasionally, such as once per round trip, to elicit an ACK from the peer. <del> A receiver MUST NOT bundle an ack-eliciting frame with all packets that would otherwise be non-ack-eliciting, to avoid an infinite feedback loop of acknowledgements. </del>  13.2.6. QUIC acknowledgements are irrevocable.  Once acknowledged, a packet remains acknowledged, even if it does not appear in a future ACK <del> frame.  This is unlike TCP SACKs (RFC2018). </del>  Packets from different packet number spaces can be identified using the same numeric value.  An acknowledgment for a packet needs to Extensions that modify or replace core protocol functionality (including frame types) will be difficult to combine with other <del> extensions which modify or replace the same functionality unless the </del>  behavior of the combination is explicitly defined.  Such extensions SHOULD define their interaction with previously-defined extensions modifying the same protocol components. An endpoint detected an error with protocol compliance that was not covered by more specific error codes. <del> A server received a Retry Token in a client Initial that is invalid. </del>  The application or application protocol caused the connection to be closed.

NAME had some useful feedback in . This doesn't address the following items as numbered in the issue: (2) Because the fix to (1) seems adequate by my reckoning. That addresses the question of considering the impact on other network users. (6) This doesn't appear to be a problem. It might be a formatting issue, with the URL not appearing. (7) This is addressed in the recent draft by adding Section  (9) and (11) I can't find the rendering glitch mentioned. The rest of these are good.
Fine and thanks for looking to these. I do think something more needs to be said about the need to avoid collateral impact on the forward traffic of this and other traffic sharing a path. To me this really important in an IETF Transport specification, especially one that might displace TCP. /It can also improve connection throughput on severely asymmetric links; see Section 3 of {{?RFC3449}}./ To me, a note to make sure this isn't ignored would seem enough, but I'd be happy to take this up as a separate WGLC comment if that seems better.
Let's take that up separately. I don't object to the language, but I just didn't know what to say.
I think there are NiTs in the second half the ID also, and while I suspectthese don't change the intended meaning, they nevertheless should be examined by the editors: (1) Concerning ACKS: I thought the following text was heading in the correct direction, but I remain concerned that this could be read to suggest that performance of the flow should drive the changes. /However, an implementer should only deviate from these requirements after careful consideration of the performance implications of doing so./ I’d love this to actually say something about congestion. Decisions made in the generation of ACKs can impact the congestion to the network and therefore also the performance of other flows that share a path. I really think we should say this. (2) And collateral impact on other traffic: /It can also improve connection throughput on severely asymmetric links; see Section 3 of {{?RFC3449}}./ It also can have important congestion impacts on other traffic that shares an asymmetric bottleneck, besides the self-harm of reducing the application’s own throughput. (3) Justify? This text seems a good recommendation, but there isn’t a hint at why this is a strong requirement, could the editors add one line of text explaining? /Senders MUST NOT coalesce QUIC packets for different connections into a single UDP datagram./ (4) The size and frequency of ACKs can impact the performance of QUIC, so there are also congestion control reasons to not overly report ACK ranges. /This is necessary if an ACK frame would be too large to fit in a packet, however receivers MAY also limit ACK frame size further to preserve space for other frames./ (5) This seems an awkward sentence and I could not understand what was intended: /A receiver MUST NOT bundle an ack-eliciting frame with all packets that would otherwise be non-ack-eliciting, to avoid an infinite feedback loop of acknowledgements./ Perhaps /all/ in this is part of my confusion? (6) In Section: Versions (missing words) /Implementors are encouraged to register version numbers of QUIC that they are using for private experimentation on the GitHub wiki at ./ either way, it may be better to complete the sentence? (7) In Section: PING Frame: (NiT) This seems good advice, but I’d love the sentence to include “to keep a connection alive”, since at the moment reading this alone, could be seen as rather general guidance. Whereas there are other uses of PINGs, such as PLPMTUD, and for this use can generate pings by clients and servers: /An application protocol SHOULD provide guidance about the conditions under which generating a PING is recommended. / e.g. /An application protocol SHOULD provide guidance about the conditions under which it recommends generating a PING to keep a connection alive./ (8) In ACKs: (NiT) /This is unlike TCP SACKs ({{?RFC2018}})./This is unlike reneging for TCP SACKs ({{?RFC2018}})./ can we be slightly more explicit about the important difference by adding a couple of words? (9) In Section: STREAM Frames (line break:) /Offset:/ The first sentence in /Offset/ appears to have an odd line-break mid sentence. (10) In Section: Extension Frames /which/that/? /other extensions which modify or replace the same functionality unless the behavior of the combination is explicitly defined./ (11) In Section: Transport Error Codes (line break:) INVALID_TOKEN (0xB): :/ The first sentence needs a line-break mid sentence. (12) In Section: Version Negotiation Is this only a recommendation? “Clients that support multiple QUIC versions SHOULD pad the first packet they send to the largest of the minimum packet sizes across all versions they support.” Whereas in Section: Packet Size /A client MUST expand the payload of all UDP datagrams carrying Initial packets to at least 1200 bytes, by adding PADDING frames to the Initial packet or by coalescing the Initial packet; see {{packet-coalesce}}./ I think the latter is true, and suspect that version negotiation section shouldn’t include this text, but instead refer to the text norm initial packet size. (13) In Section: Cryptographic and Transport Handshake Is this intended as optional, I think it is required when ECN is to be used? “An endpoint can verify support for Explicit Congestion Notification (ECN) in the first packets it sends, as described in {{ecn-validation}}.” seems to suggest this is optional, whereas, I think actually this is describing a needed mechanism, so is it better to say “An endpoint verifies” as is done in the section: Initiating Connection Migration. which says: “The new path might not have the same ECN capability. Therefore, the endpoint verifies ECN capability as described in {{ecn}}.”
Let's get these in and deal with more specific issues separately.

The size of the first packet sent by a client will determine whether a server sends a Version Negotiation packet.  Clients that support  <ins> multiple QUIC versions SHOULD pad the first UDP datagram they send to the largest of the minimum datagram sizes from all versions they support.  This ensures that the server responds if there is a mutually supported version. </ins> 6.1. authenticated negotiation of an application protocol (TLS uses ALPN RFC7301 for this purpose)  <ins> An endpoint verifies support for Explicit Congestion Notification </ins> (ECN) in the first packets it sends, as described in ecn-validation. The CRYPTO frame can be sent in different packet number spaces endpoint SHOULD NOT coalesce multiple packets at the same encryption level.  <ins> Receivers MAY route based on the information in the first packet contained in a UDP datagram.  Senders MUST NOT coalesce QUIC packets for different connections into a single UDP datagram.  Receivers SHOULD ignore any subsequent packets with a different Destination Connection ID than the first packet in the datagram. </ins> Every QUIC packet that is coalesced into a single UDP datagram is separate and complete.  The receiver of coalesced QUIC packets MUST The algorithms in QUIC-RECOVERY are expected to be resilient to receivers that do not follow guidance offered above.  However, an  <ins> implementation should only deviate from these requirements after careful consideration of the performance implications of a change, for connections made by the endpoint and for other users of the network. </ins> An endpoint that is only sending ACK frames will not receive acknowledgments from its peer unless those acknowledgements are frame to become too large.  A receiver can discard unacknowledged ACK Ranges to limit ACK frame size, at the cost of increased retransmissions from the sender.  This is necessary if an ACK frame  <ins> would be too large to fit in a packet.  Receivers MAY also limit ACK frame size further to preserve space for other frames or to limit the capacity that acknowledgments consume. </ins> A receiver MUST retain an ACK Range unless it can ensure that it will not subsequently accept packets with numbers in that range. bundle a PING or other small ack-eliciting frame occasionally, such as once per round trip, to elicit an ACK from the peer.  <ins> A receiver MUST NOT bundle an ack-eliciting frame with packets that would otherwise be non-ack-eliciting, to avoid an infinite feedback loop of acknowledgements. </ins> 13.2.6. QUIC acknowledgements are irrevocable.  Once acknowledged, a packet remains acknowledged, even if it does not appear in a future ACK  <ins> frame.  This is unlike reneging for TCP SACKs (RFC2018). </ins> Packets from different packet number spaces can be identified using the same numeric value.  An acknowledgment for a packet needs to Extensions that modify or replace core protocol functionality (including frame types) will be difficult to combine with other  <ins> extensions that modify or replace the same functionality unless the </ins> behavior of the combination is explicitly defined.  Such extensions SHOULD define their interaction with previously-defined extensions modifying the same protocol components. An endpoint detected an error with protocol compliance that was not covered by more specific error codes.  <ins> A server received a client Initial that contained an invalid Token field. </ins> The application or application protocol caused the connection to be closed.


bytes in length.  Connection IDs are described in connection-id. The next byte contains the length in bytes of the Source Connection <del> ID field that follows it.  This length is encoded as a 8-bit unsigned integer.  The Source Connection ID field follows the Source </del>  Connection ID Length field and is between 0 and 255 bytes in length. The remainder of the packet contains version-specific content. fields, or a truncated Supported Version. Version Negotiation packets do not use integrity or confidentiality <del> protection.  A specific QUIC version might authenticate the packet as part of its connection establishment process. </del>  An endpoint MUST include the value from the Source Connection ID field of the packet it receives in the Destination Connection ID

My WGLC feedback for -invariants is mostly nits, so I figured I'd go straight to a PR. There's one piece of this that might be non-editorial; feel free to kick to an issue if you prefer. In one section, we say that different versions "might" define authentication for VN packets. Later, we say that QUIC versions MUST define such a mechanism. Resolving in favor of the MUST, I've changed the other occurrence to a more definitive statement that QUIC versions do so.
Thanks Mike.

bytes in length.  Connection IDs are described in connection-id. The next byte contains the length in bytes of the Source Connection  <ins> ID field that follows it.  This length is encoded as an 8-bit unsigned integer.  The Source Connection ID field follows the Source </ins> Connection ID Length field and is between 0 and 255 bytes in length. The remainder of the packet contains version-specific content. fields, or a truncated Supported Version. Version Negotiation packets do not use integrity or confidentiality  <ins> protection.  Specific QUIC versions define mechanisms to authenticate the packet as part of the connection establishment process. </ins> An endpoint MUST include the value from the Source Connection ID field of the packet it receives in the Destination Connection ID


In order to drive the handshake, TLS depends on being able to send and receive handshake messages.  There are two basic functions on this interface: one where QUIC requests handshake messages and one <del> where QUIC provides handshake packets. </del>  Before starting the handshake QUIC provides TLS with the transport parameters (see quic_parameters) that it wishes to carry. Each encryption level is associated with a different sequence of bytes, which is reliably transmitted to the peer in CRYPTO frames. When TLS provides handshake bytes to be sent, they are appended to <del> the current flow.  Any packet that includes the CRYPTO frame is protected using keys from the corresponding encryption level.  Four encryption levels are used, producing keys for Initial, 0-RTT, </del>  Handshake, and 1-RTT packets.  CRYPTO frames are carried in just three of these levels, omitting the 0-RTT level.  These four levels correspond to three packet number spaces: Initial and Handshake When an endpoint receives a QUIC packet containing a CRYPTO frame from the network, it proceeds as follows: <del> If the packet was in the TLS receiving encryption level, sequence the data into the input flow as usual.  As with STREAM frames, the offset is used to find the proper location in the data sequence. If the result of this process is that new data is available, then it is delivered to TLS in order. </del>  If the packet is from a previously installed encryption level, it MUST NOT contain data which extends past the end of previously If the packet is from a new encryption level, it is saved for later processing by TLS.  Once TLS moves to receiving from this <del> encryption level, saved data can be provided.  When providing data from any new encryption level to TLS, if there is data from a previous encryption level that TLS has not consumed, this MUST be treated as a connection error of type PROTOCOL_VIOLATION. </del>  Each time that TLS is provided with new data, new handshake bytes are requested from TLS.  TLS might not provide any bytes if the handshake messages it has received are incomplete or it has no data to send.  Once the TLS handshake is complete, this is indicated to QUIC along with any final handshake bytes that TLS needs to send.  TLS also provides QUIC with the transport parameters that the peer advertised

This also adds a paragraph about buffering of CRYPTO frames that references the buffering text in the transport doc. Closes no issue, but there have been complaints.

In order to drive the handshake, TLS depends on being able to send and receive handshake messages.  There are two basic functions on this interface: one where QUIC requests handshake messages and one  <ins> where QUIC provides bytes that comprise handshake messages. </ins> Before starting the handshake QUIC provides TLS with the transport parameters (see quic_parameters) that it wishes to carry. Each encryption level is associated with a different sequence of bytes, which is reliably transmitted to the peer in CRYPTO frames. When TLS provides handshake bytes to be sent, they are appended to  <ins> the handshake bytes for the current encryption level.  Any packet that includes the CRYPTO frame is protected using keys from the corresponding encryption level. Four encryption levels are used, producing keys for Initial, 0-RTT, </ins> Handshake, and 1-RTT packets.  CRYPTO frames are carried in just three of these levels, omitting the 0-RTT level.  These four levels correspond to three packet number spaces: Initial and Handshake When an endpoint receives a QUIC packet containing a CRYPTO frame from the network, it proceeds as follows:  <ins> If the packet uses the current TLS receiving encryption level, sequence the data into the input flow as usual.  As with STREAM frames, the offset is used to find the proper location in the data sequence.  If the result of this process is that new data is available, then it is delivered to TLS in order. </ins> If the packet is from a previously installed encryption level, it MUST NOT contain data which extends past the end of previously If the packet is from a new encryption level, it is saved for later processing by TLS.  Once TLS moves to receiving from this  <ins> encryption level, saved data can be provided to TLS.  When providing data from any new encryption level to TLS, if there is data from a previous encryption level that TLS has not consumed, this MUST be treated as a connection error of type PROTOCOL_VIOLATION. </ins> Each time that TLS is provided with new data, new handshake bytes are requested from TLS.  TLS might not provide any bytes if the handshake messages it has received are incomplete or it has no data to send. <ins> The content of CRYPTO frames might either be processed incrementally by TLS or buffered until complete messages or flights are available. TLS is responsible for buffering handshake bytes that have arrived in order.  QUIC is responsible for buffering handshake bytes that arrive out of order or for encryption levels that are not yet ready.  QUIC does not provide any means of flow control for CRYPTO frames; see Section 7.5 of QUIC-TRANSPORT. </ins> Once the TLS handshake is complete, this is indicated to QUIC along with any final handshake bytes that TLS needs to send.  TLS also provides QUIC with the transport parameters that the peer advertised


the frame.  These frames are explained in more detail in frame- formats. <del> The "Packets" column in frame-types does not form part of the IANA registry; see iana-frames.  This column lists the types of packets that each frame type could appear in, indicated by the following characters: </del>  Initial (packet-initial) Section 4 of QUIC-TLS provides more detail about these restrictions. Note that all frames can appear in 1-RTT packets.  An endpoint MUST treat the receipt of a frame of unknown type as a connection error of type FRAME_ENCODING_ERROR. format and assigned semantics of any fields in the frame. The initial contents of this registry are tabulated in frame-types. <del> Note that the registry does not include the "Packets" column from frame-types. </del>  22.4.

After considering this a little more it seems helpful to bring some of the special handling rules up into the summary. We don't really give up-front treatment of ack-eliciting, probing, and other important distinctions, so an extra column seemed useful. A table of this size just fits in the text format.
I had almost exactly those changes in a previous version. It was a near thing.
That is super helpful, and is the direction I was hoping for!
In Section Frame Types and Formats, there is a very useful summary of frame types by packet type. As a person with a CC and transport protocol interest, it would be really nice to have had a summary table of key properties that included whether each frame type is ack-eliciting; whether transmission is controlled by flow-control; and whether transmission is controlled by congestion-control. Is there any chance we can add an extra column say to this table?
The problem with the table is that it is already essentially the full width available to us. That makes the addition of more information quite difficult. The rules for most of these are simple enough that I'm not sure that the table is the best way to present it. That is: ack-eliciting: all except ACK, PADDING congestion-controlled: all except ACK flow controlled: only STREAM
I wouldn't want to mess-up the table format to include the info. However, it would be really nice to have the info in a compact way close to the table somehow so that readers quickly confirm this. Would a note below the table possibly work, saying just this?

the frame.  These frames are explained in more detail in frame- formats.  <ins> The "Pkts" column in frame-types lists the types of packets that each frame type could appear in, indicated by the following characters: </ins> Initial (packet-initial) Section 4 of QUIC-TLS provides more detail about these restrictions. Note that all frames can appear in 1-RTT packets. <ins> The "Spec" column in frame-types summarizes any special rules governing the processing or generation of the frame type, as indicated by the following characters: Packets containing only frames with this marking are not ack- eliciting; see generating-acks. Packets containing only frames with this marking do not count toward bytes in flight for congestion control purposes; see QUIC- RECOVERY. Packets containing only frames with this marking can be used to probe new network paths during connection migration; see probing. The content of frames with this marking are flow controlled; see flow-control. The "Pkts" and "Spec" columns in frame-types do not form part of the IANA registry; see iana-frames. </ins> An endpoint MUST treat the receipt of a frame of unknown type as a connection error of type FRAME_ENCODING_ERROR. format and assigned semantics of any fields in the frame. The initial contents of this registry are tabulated in frame-types.  <ins> Note that the registry does not include the "Pkts" and "Spec" columns from frame-types. </ins> 22.4.


13.4.2.2. <del> An endpoint that sets ECT(0) or ECT(1) codepoints on packets it transmits MUST use the following steps on receiving an ACK frame to validate ECN. If this ACK frame newly acknowledges a packet that the endpoint sent with either ECT(0) or ECT(1) codepoints set, and if no ECN feedback is present in the ACK frame, validation fails.  This step protects against both a network element that zeroes out ECN bits and a peer that is unable to access ECN markings, since the peer could respond without ECN feedback in these cases. For validation to succeed, the total increase in ECT(0), ECT(1), and CE counts MUST be no smaller than the total number of QUIC packets sent with an ECT codepoint that are newly acknowledged in this ACK frame.  This step detects any network remarking from ECT(0), ECT(1), or CE codepoints to Not-ECT. Any increase in either ECT(0) or ECT(1) counts, plus any increase in the CE count, MUST be no smaller than the number of packets sent with the corresponding ECT codepoint that are newly acknowledged in this ACK frame.  This step detects any erroneous network remarking from ECT(0) to ECT(1) (or vice versa). Processing ECN counts out of order can result in validation failure. An endpoint SHOULD NOT perform this validation if this ACK frame does not advance the largest packet number acknowledged in this connection. </del>  An endpoint could miss acknowledgements for a packet when ACK frames are lost.  It is therefore possible for the total increase in ECT(0), <del> ECT(1), and CE counts to be greater than the number of packets acknowledged in an ACK frame.  When this happens, and if validation succeeds, the local reference counts MUST be increased to match the counts in the ACK frame. </del>  13.4.2.3.

This avoids "no smaller than", unqualified "total increase", and other such ambiguities. However, in doing this, I realized that I might interpret the original language as allowing a network to ADD markings. That seems wrong. But it's a non-editorial change. This version has that change. I'll make another PR with the hole left in place in case I'm wrong.
OK, I realize now my mistake. The draft allows for an increase because of the possibility of ACK loss. Counts might increase more than there are newly acknowledged packets because an endpoint might not receive an ACK for every packet that is accounted for in the increased count. I think that's worth a note. Though now I'm concerned about the third clause, which doesn't include any protection against this problem. I'll open an issue for that.
Sorry to ask for another review, but I had a few misfires yesterday (apparently). I think that this structure is much better. I have removed the check that uses the sum of ECT0+ECT1+CE. Any check on ECT0+CE or ECT1+CE is more precise anyway. The sum is only able to detect double-counting of CE-marked packets, but as the check is an inequality, we would allow what to happen. (That was what motivated my proposed additional check, but I agree that is not worth documenting.)
QUIC doesn't guarantee that every received packet will be acknowledged. At the same time, ECN validation uses counts of every received packet. The net effect of this is captured in this statement: -- URL For example, if a sender sends 10 ECT-marked packets and all of them arrive, they might only receive acknowledgments for 8 of these. The receiver will still report an increase of 10 for the corresponding markings. The sender compensates for this error by allowing this deviation and using the new reference number for future packets. Note that validation also depends on the receiver counting but not acknowledging a packet, then later changing its mind and acknowledging the packet. We don't state this, but we shouldn't have to. But that allowance only applies to the validation performed on the sum of ECT(0), ECT(1) and ECN-CE counts. The validation for cross-marking of ECT(0) to ECT(1) or vice versa does not include this same protection. Thus, failure to acknowledge a packet will probably result in ECN validation failing. There are a few ways we might fix this. We could just allow for an increase here too. The net effect though is that we don't get to watch for cross-marking. We don't get any protection against cross marking like this. In other words, we can remove the check. It might be better to limit the allowed increase by the total excess in the total. That is, if then the check is and . The combined check becomes . That is, increases to ECT(X) + CE above what was newly acknowledged has to be represented in the total unaccounted value. If all unaccounted packets were CE marked, then they will be unaccounted for twice in the individual counts. If none of the unaccounted packets were CE marked, then they will be counted just once. That suggests the following text for the third check: This third check is now more precise than the second check, so I would suggest removing the combined check that we have current as step 2. A new combined check might detect remarking between ECT(0) and ECT(1): And finally, because most stacks only apply one type of marking:
I'm not convinced this needs fixing. To your point above: It is an exceedingly rare corner case, since this requires an ACK for a packet to not be sent or received, and then for there to be cross-marking within that fraction of connections. And in this case, ECN validation fails and is turned off. We knew corner cases existed, but we also had the escape hatch of turning off ECN when things were not "quite right". Why is that answer not good enough any more? (Or am I missing something?)
The problem is that we fixed this in one place, but not another. And we explicitly call out the need for the fix. The goal of validation was - by my understanding - finding obvious mistakes. But this creates false positives. If we want to do something minimal, then I would suggest that we simplify. That is, reduce the checks to or .
That's how I read the third validation check: but I agree it's not very clear. I think the intent was to do the minimal version you suggest above (which is why it's "either" instead of "both" in the text). I would be happy with us clarifying the text to say that more clearly.
Before this gets stuck. I'm abandoning this.
So, I am finally implementing this, and have questions. Section 13.4.2.2 says: What is meant by "total increase" here? I guess it is a delta, but against what? Against the values in the last received ACK frame? Against the "local reference counts" (which aren't really described well either, see below)? Or something else? Also, I guess the "total increase" compared here is a sum of these individual deltas? Again, "increase" relative to what? Same question about "total increase". And what are the "local reference counts", and how are they maintained?
You are supposed to keep three counters for the number of each ECT(0) and ECT(1) and CE marks reported so far on this connection (for this ack space). Increase means the difference of the count reported in the latest ACK compared to the current local counter value. Total increase is increase of ECT(0)+increase of ECT(1)+increase if CE compared to local current count of ECT(0)+ECT(1)+CE. Does that help?
It does, thanks. It would probably be useful to introduce those local reference counts before the bullet list, describe how they are maintained, and then use them when describing how to validate.
Yes. Will try to propose a PR. Thanks for implementing!
Actually, this doesn't make sense to me: The increase is the value in the current ACK frame minus the current local reference value. A sum of those increases is always going to be less than the sum of the total reference values?
Yes, sorry, in the text you don't compare the total increase to the local value of course. You compare the total increase to the number of packets acknowledged in an ACK frame
and then you also compare the increase of ECT(0)+increase in CE to number of packet sent with ECT(0) from the newly acknowledge packets, and same for ETC(1). So you need to remember which packet was sent with which ECN codepoint if not all packets are send with the same codepoint.
So let me tell you what my code is doing now to verify incoming ACK-ECNs, and then you tell me if this is correct: I maintain ECN reference counter vectors () per packet number space. These hold the last counts received in an ACK-ECN from the peer. I count new ACKs for ECN-marked packets that I sent in a vector. (I only send ECNECT0 packets though, so this isn't really a vector, just a variable.) When I receive a new ACK-ECN with ECN counts (), I compute the vector as . I then do the verification per Section 13.4.2.2: (First bullet in 13.4.2.2 is easy, omitted here) Second bullet in 13.4.2.2: => verification failed Third bullet in 13.4.2.2: => verification failed. (Since I only send ECNECT0, I can omit looking at ECNECT1, I believe.) If verification succeeds, I assign . If it fails, I stop sending ECNECT0 marked packets, and I stop trying to verify any future ACK-ECN information.
NAME ping?
Sorry, long weekend in Germany. Yep this sounds right. If you only have ECT(0), you can simplify test 2 to just do what you do in 3 ('ecninc[ECNECT0] + ecncnt[ECNCE] < newack[ECNECT0]') and for test 3 you just need to check if there are any ECT(1) marking at all and fail if you ever get feedback that ECT(1) was observed.
Maybe use <= rather than < though.
NAME I'm not sure that's correct?
Oh yes, didn't see that. I also think it should be <= . NAME why do think it should be < ?
Because if the number of marked packets in the ACK is == the number of marked packets I sent, that is not a verification failure? (Or am I misunderstanding something?)
Right... I got confused that the condition is about moving into failure mode. So usually the numbers should always be exactly equal; only if some marked packets get not ack'ed at all the received count could be larger than the number of marked sent and ack'ed packet. I guess, if you know that this is not the case you could be even stricter. Otherwise if there are no unack'ed packets and the received count would be larger, it would mean you have some remarking from Not-ECT to ECT or CE. That less a problem in terms of hiding congestion but might still indicate that something is wrong... however, given that you mark all packet in your implementation with ECT(0) that case should not happen.
And as noted the primary failure mode where increase of reference counter can be larger than newely ACKed packets is lost ACKs. Section 13.4.1 is clear on that duplicate packets shall be surpressed prior to increasing the relevant ECN counter.

13.4.2.2.  <ins> Erroneous application of ECN marks in the network can result in degraded connection performance.  An endpoint that receives an ACK frame with ECN counts therefore validates the counts before using them.  It performs this validation by comparing newly received counts against those from the last successfully processed ACK frame.  Any increase in ECN counts is validated based on the markings that were applied to packets that are newly acknowledged in the ACK frame. If an ACK frame newly acknowledges a packet that the endpoint sent with either ECT(0) or ECT(1) codepoints set, ECN validation fails if ECN counts are not present in the ACK frame.  This check detects a network element that zeroes out ECN bits or a peer that is unable to access ECN markings. ECN validation fails if the sum of the increase in ECT(0) and ECN-CE counts is less than the number of newly acknowledged packets that were originally sent with an ECT(0) marking.  Similarly, ECN validation fails if the sum of the increases to ECT(1) and ECN-CE counts is less than the number of newly acknowledged packets sent with an ECT(1) marking.  These checks can detect removal of ECN markings in the network. </ins> An endpoint could miss acknowledgements for a packet when ACK frames are lost.  It is therefore possible for the total increase in ECT(0),  <ins> ECT(1), and ECN-CE counts to be greater than the number of packets acknowledged in an ACK frame.  This is why counts are permitted to be larger than might be accounted for by newly acknowledged packets. ECN validation MAY fail if the total count for an ECT(0) or ECT(1) marking exceeds the total number of packets sent with the corresponding marking.  In particular, an endpoint that never applies a particular marking can fail validation when a non-zero count for the corresponding marking is received.  This check can detect when packets are marked ECT(0) or ECT(1) in the network. Processing ECN counts out of order can result in validation failure. An endpoint SHOULD skip ECN validation on an ACK frame that does not increase the largest acknowledged packet number. </ins> 13.4.2.3.


first byte being set; packets with a short header have that bit cleared.  Aside from the values described here, the payload of QUIC packets is version-specific and of arbitrary length. 5.4. <del> QUIC versions are identified with a 32-bit integer, encoded in network byte order.  Version 0 is reserved for version negotiation (see version-negotiation).  All other version numbers are potentially valid. </del>  The properties described in this document apply to all versions of QUIC.  A protocol that does not conform to the properties described

URL's just a Version field. This is a subtle one, but it follows from the work that others have been doing on greasing versions or providing additions to echconfig for QUIC connection establishment. It basically says that Version is for endpoints, not middleboxes.
I like the idea here, but it seems like the distinction in the text is too subtle. Why not remove this entirely?
By "this", do you mean striking ?
I was actually suggesting removing it from invariants entirely.
I would quibble a bit about whether or not version aliasing really violates the existing text, but I still think this change is a good one. For example, if we fail to prevent ossification then we're going to end up with this being the "fake" version while the real version is buried in the TPs.
The invariants spec currently defines Version thusly: This implies that packets in which this field is present are packets for connections that use the associated version. An overzealous, but not unreasonable interpretation of this might lead to a middlebox looking at Version=N and assuming that the packet conforms to QUIC version N. Actions taken on that basis might be detrimental, especially if we consider options like those proposed in draft-duke-quic-version-aliasing or draft-kazuho-quic-authenticated-handshake. In other words, this commits us to something we already know we might not want to commit to. It would be better to simply state the format of the field and that it is used by endpoints to identify the version. I have done this in .
There seems to be support for this issue and , and the change is editorial.
As an individual, I wonder if it would be worthwhile to add text to the draft that explicitly calls out that it is not safe for anybody other than the endpoints to assume knowledge about what protocol version an observed version number refers to. I think this it the implicit goal, making it explicit is IMO more direct. (This could also be something for the ops-drafts to talk about though.)
NAME relabelled the PR as design a few days ago, so it this potentially a design issue?
Looking at the diff, I don't really see a need for labelling it design. NAME why the design label?
It's a subtle change, but it is a change in the design of the invariants. It's saying that a packet marked version 0x13 isn't necessarily carrying a packet encoded in version 0x13, even if an observer speaks that version. Merely that the bytes 0x00000013 are somehow useful to the recipient in identifying the version. Previously, we made the assertion that the version field indicated what version was used in the packet.
Let's run this through the design issue process to be sure.
So it seems we have a resolution in . Labelling as such.

first byte being set; packets with a short header have that bit cleared. <ins> QUIC packets might be integrity protected, including the header. However, QUIC Version Negotiation packets are not integrity protected; see vn. </ins> Aside from the values described here, the payload of QUIC packets is version-specific and of arbitrary length. 5.4.  <ins> The Version field contains a 4-byte identifier.  This value can be used by endpoints to identify a QUIC Version.  A Version field with a value of 0x00000000 is reserved for version negotiation; see vn.  All other values are potentially valid. </ins> The properties described in this document apply to all versions of QUIC.  A protocol that does not conform to the properties described


first byte being set; packets with a short header have that bit cleared.  Aside from the values described here, the payload of QUIC packets is version-specific and of arbitrary length. QUIC versions are identified with a 32-bit integer, encoded in network byte order.  Version 0 is reserved for version negotiation <del> (see version-negotiation).  All other version numbers are potentially valid. </del>  The properties described in this document apply to all versions of QUIC.  A protocol that does not conform to the properties described

Or MAY, but let's leave this probabilistic, because in practice there is no uncertainty: packets are protected. I've changed the header of the section because it isn't just about the header: the subsections are about the specific headers, but this one is about packets as a whole.

first byte being set; packets with a short header have that bit cleared. <ins> QUIC packets might be integrity protected, including the header. However, QUIC Version Negotiation packets are not integrity protected; see vn. </ins> Aside from the values described here, the payload of QUIC packets is version-specific and of arbitrary length. QUIC versions are identified with a 32-bit integer, encoded in network byte order.  Version 0 is reserved for version negotiation  <ins> (see vn).  All other version numbers are potentially valid. </ins> The properties described in this document apply to all versions of QUIC.  A protocol that does not conform to the properties described


HTTP/1.1 HTTP11 is a TCP mapping which uses whitespace-delimited text fields to convey HTTP messages.  While these exchanges are human- readable, using whitespace for message formatting leads to parsing <del> complexity and motivates tolerance of variant behavior.  Because each connection can transfer only a single HTTP request or response at a time in each direction, multiple parallel TCP connections are often used, reducing the ability of the congestion controller to effectively manage traffic between endpoints. </del>  HTTP/2 HTTP2 introduced a binary framing and multiplexing layer to improve latency without modifying the transport layer.  However,

NAME raised the point that the following text might be misleading, since HTTP/1.1 allows pipelining: "HTTP/1.1 [HTTP11] is a TCP mapping which uses whitespace-delimited text fields to convey HTTP messages. While these exchanges are human-readable, using whitespace for message formatting leads to parsing complexity and motivates tolerance of variant behavior. Because each connection can transfer only a single HTTP request or response at a time in each direction, multiple parallel TCP connections are often used, reducing the ability of the congestion controller to effectively manage traffic between endpoints." NAME suggested the following text instead: "Because of limitations in how HTTP exchanges are mapped onto TCP connections in HTTP/1.1, multiple parallel connections are often used..." NAME suggested the following text instead: "Because HTTP/1.x does not include a multiplexing layer, multiple TCP connections are often used to service requests in parallel. However, that has a negative impact on congestion control and network efficiency, since TCP does not share congestion control across multiple connections."
Roy's works for me.

HTTP/1.1 HTTP11 is a TCP mapping which uses whitespace-delimited text fields to convey HTTP messages.  While these exchanges are human- readable, using whitespace for message formatting leads to parsing  <ins> complexity and motivates tolerance of variant behavior.  Because HTTP/1.x does not include a multiplexing layer, multiple TCP connections are often used to service requests in parallel.  However, that has a negative impact on congestion control and network efficiency, since TCP does not share congestion control across multiple connections. </ins> HTTP/2 HTTP2 introduced a binary framing and multiplexing layer to improve latency without modifying the transport layer.  However,


an entire round trip, and potentially for longer if the peer chooses not to send STREAMS_BLOCKED frames.  5. QUIC's connection establishment combines version negotiation with the

QUIC doesn't really address the question of tuning flow control very well. This just admits that fact. It also indicates why: which essentially boils down to "RAM is cheap".
Hi Martin. I stumbled across this. I don't know if you are joking, but if not I'd like to disagree. There are a significant class of devices, commodity streaming devices, which are very large volume but for which the trend is to shave as much RAM budget as possible, HD video devices in markets like India, Brazil, etc. In aggregate, these devices consume a significant amount of overall internet traffic. RAM is cheap is most definitely not true there, and they certainly don't ship with TCP receive windows anywhere near as large as other device segments. This is not a legacy issue either, for the foreseeable future it looks like the amount of RAM in newer devices will be lucky to stay stable as opposed to even decrease.
Section: Flow Control {#flow-control} The present text only states the reasons why flow control limits are needed, and resource commitments. It does not yet motivate the use of adding credit when this is needed - which is also an important design consideration for a user of QUIC transport, as it is for http. That is, the section should also state the performance implications of too little credit - i.e. the tradeoff, by explaining: “Advertising too little credit will cause the stream to become blocked and can limit performance when it constrains a stream path using a path that has large bandwidth delay product”. Section: Flow Credit Increments The following could be taken as a general guidance, when the ID says: “As an optimization, an endpoint could send frames related to flow control only when there are other frames to send or when a peer is blocked, ensuring that flow control does not cause extra packets to be sent.” I do not agree. This appears an optimisation for minimising resource use. It will I expect have a serious negative impact on performance where the path RTT is large, and that case also needs to be mentioned. This is an area where guidance is needed, since the way TCP operates is not described in the RFC series and mistakes in this part of the code can have very serious impacts on the performance and dynamics of applications, as well as the patterns of traffic on the wire. Section: Flow Credit Increments The following could be taken as a general guidance, when the ID says: “When a sender receives credit after being blocked, it might be able to send a large amount of data in response, resulting in short-term congestion; see Section 6.9 in {{QUIC-RECOVERY}} for a discussion of how a sender can avoid this congestion.” I think this sentence may be well-intended but can be read as encouraging an unsafe practice. There is considerable latitude in how to design flow control, but read the current words as suggesting that the induced congestion from large updates are actually OK - which I do not think the IETF should say. To me this requires words of caution to avoid the large bursts.
The following could be taken as a general guidance, when the ID says: “As an optimization, an endpoint could send frames related to flow control only when there are other frames to send or when a peer is blocked, ensuring that flow control does not cause extra packets to be sent.” Even if RTT < 40ms we saw a negative impact of this optimization in our quic implementation
NAME Can you clarify what conditions you're testing, as there are are a lot of variables in flow control. We send flow control updates much less frequently than anytime there's free credit and a packet is already being sent, and very rarely see flow control blockage, despite doing dynamic window tuning on the server side. So I'd expect if we did more proactive updates with better bundling, it'd only help. Bundling flow control updates with ACK frames makes a large amount of sense, because ACK frames free up congestion window space and window updates free up flow control.
NAME We used simply conditions: sender is not app-limited, we tested FC for different bottleneck links e.g. 100Mbps, 1Gbps and different FC Limits, RTT was between 1ms und 100ms with step 10. We do not used dynamic window tuning as it’s not defined in draft as a MUST. I think it’s an interesting idea to bundle FC updates with ACK frames (if ACK must be sent every other packet). But in the case of bundling, I expect, that ackRatio parameter (e.g. equal to 10) would influence the frequency of FC-updates and thereby QUIC performance. I can implement und explore it in our implementation. In order to have a possibility to test FC appropriate and provide comparable results, I wish, that the FC algorithm would be better defined in QUIC transport draft e.g. with a pseudocode.
I think that there are things that might be said about this point: Unlike TCP, QUIC decouples flow control from congestion control. This can release pressure on having a good flow control algorithm. An endpoint can use flow control to constrain resource commitments without paying specific attention to tuning the algorithm. An endpoint might therefore implement a suboptimal flow control algorithm without incurring performance penalties, up to the point where the BDP approaches the size of buffers the endpoint allocates for receiving data. If buffers are not significantly larger than the BDP, an endpoint needs to provide flow control updates in a timely fashion if it wishes to avoid flow control limiting throughput. An endpoint that is unable to ensure that a peer has flow control credit in the order of the BDP will have their throughput limited by flow control and not other limiting factors like congestion control. (It's a little more complicated than that, as losses are discovered and repaired over a period larger than an RTT, and then you have to allow for flow control updates being lost. The real value you need to target is therefore likely to be something more than 9/8 times the BDP. But I think that gets the idea across.)
I've just opened an editorial PR that fixes this. This is based on my previous comments here. However, I think that we should try to achieve consensus on the views contained therein. Though the alternative is scary, I want to make sure that we are intentionally choosing not to document "good" flow control algorithms.
Would folks please comment (here) on whether addresses this issue?
I think explicitly calling this out as a trade-off that implementations will need to experiment with, but which does not affect protocol interoperability is the correct path here. Flow control is a mechanism, not an algorithm.
I believe addresses the issue and long ago we agreed not to document an exact algorithm.

an entire round trip, and potentially for longer if the peer chooses not to send STREAMS_BLOCKED frames. <ins> 4.6. An endpoint that is unable to ensure that a peer has flow control credit on the order of the current BDP will have receive throughput limited by flow control.  Lost packets can cause gaps in the receive buffer, delaying the application from consuming data and freeing up flow control window. Sending timely updates of flow control limits can improve performance.  Sending packets only to provide flow control updates can increase network load and adversely affect performance.  Sending flow control updates along with other frames, such as ACK frames, reduces the cost of those updates. </ins> 5. QUIC's connection establishment combines version negotiation with the


The IPv6 flow label SHOULD be a pseudo-random function of the source and destination addresses, source and destination UDP ports, and the <del> destination CID.  The flow label generation MUST be designed to minimize the chances of linkability with a previously used flow label, as this would enable correlating activity on multiple paths; see migration-linkability. </del>  A possible implementation is to compute the flow label as a cryptographic hash function of the source and destination addresses, <del> source and destination UDP ports, destination CID, and a local secret. </del>  10.

We've been pretty disciplined about using "connection ID", except for the text on flow labels and one mention in the diagram for preferred_address. Of course, the mentions in the flow label text were specifically for the "Destination Connection ID field", so that is what I used there.
"Use of IPv6 Flow-Label and Migration" and the definition of "preferred_address" both reference "CID" without that abbreviation of Connection ID having been defined elsewhere. It's pretty obvious, but the text for IPv6 should probably just write out connection ID in long form.

The IPv6 flow label SHOULD be a pseudo-random function of the source and destination addresses, source and destination UDP ports, and the  <ins> Destination Connection ID field.  The flow label generation MUST be designed to minimize the chances of linkability with a previously used flow label, as this would enable correlating activity on multiple paths; see migration-linkability. </ins> A possible implementation is to compute the flow label as a cryptographic hash function of the source and destination addresses,  <ins> source and destination UDP ports, Destination Connection ID field, and a local secret. </ins> 10.


The server's preferred address is used to effect a change in server address at the end of the handshake, as described in <del> preferred-address.  The format of this transport parameter is shown in fig-preferred-address.  This transport parameter is only sent by a server.  Servers MAY choose to only send a preferred address of one address family by sending an all-zero address and port (0.0.0.0:0 or ::.0) for the other family.  IP addresses are </del>  encoded in network byte order.  The Connection ID field and the Stateless Reset Token field contain an alternative connection ID that has a sequence number of 1; see issue-cid.  Having these values bundled with the preferred

In section 18.2, the definition of preferred_address says: In section 1.3, we say: The prose does not define the sequence of fields in this transport parameter.
Thanks for catching that I was looking at the wrong TP definition and knowing what I meant. Eyes glaze over indeed!

The server's preferred address is used to effect a change in server address at the end of the handshake, as described in  <ins> preferred-address.  This transport parameter is only sent by a server.  Servers MAY choose to only send a preferred address of one address family by sending an all-zero address and port (0.0.0.0:0 or ::.0) for the other family.  IP addresses are </ins> encoded in network byte order. <ins> The preferred_address transport parameter contains an address and port for both IP version 4 and 6.  The four-byte IPv4 Address field is followed by the associated two-byte IPv4 Port field. This is followed by a 16-byte IPv6 Address field and two-byte IPv6 Port field.  After address and port pairs, a Connection ID Length field describes the length of the following Connection ID field. Finally, a 16-byte Stateless Reset Token field includes the stateless reset token associated with the connection ID.  The format of this transport parameter is shown in fig-preferred- address. </ins> The Connection ID field and the Stateless Reset Token field contain an alternative connection ID that has a sequence number of 1; see issue-cid.  Having these values bundled with the preferred


The primary goal of this document is to ensure that it is possible to deploy new versions of QUIC.  By documenting the properties that <del> can't change, this document aims to preserve the ability to change any other aspect of the protocol.  Thus, unless specifically described in this document, any aspect of the protocol can change between different versions. </del>  bad-assumptions is a non-exhaustive list of some incorrect assumptions that might be made based on knowledge of QUIC version 1;

This is a reduction of to the important (and accurate) piece.
I started a thread on the mailing list URL And the general sense of it was that this text was insufficiently clear about the normative requirements it was creating. I believe this issue is editorial.
I agree that this is editorial, but I think that we should say something that is subtly different. There are two parts to your PR. One part that attempts to describe what is normative in the document. The other part attempts to more clearly describe the intent of the document: basically that anyone who looks at QUIC from the outside can only see and use this much of the protocol. For the "normative" piece, we can probably say something less concrete but more principled. That is: a protocol that follows the requirements in this document may call itself QUIC. And that any attempt to treat QUIC generically MUST be limited to using the characteristics that are included in this definition. For the intent part, I would say that the goal is to carve out a space for endpoints to communicate without interference from others. The goal is to design a protocol where participation by others only occurs with the express permission of endpoints. (I think we should be careful not to say whether this is just one or both endpoints granting permission here, because QUICv1 is a little inconsistent on this point itself.) That's somewhat stronger than the position you take. Leaving "others" unspecified here is good. I see that you have tried to define those others, but I don't think that's helpful. The nice thing about this approach is that it requires far less text. Your PR doubles the size of the draft. BTW, I do like the MUST regarding treatment of unknown versions. That is, if an entity doesn't understand what is going on then it can only apply generic treatment. But we all know that's RFC 6919 language.
NAME thanks for your thoughts. I tried to avoid language like "The QUIC WG MUST observe these invariants in future versions of QUIC". It seemed futile to have the WG constrain its future self in this way, while requirements for intermediaries would at least be actionable. I will add a recommendation for explicit cooperation; this is a good idea. Though I think there are cases, like measurement, where it isn't necessary. I think illustrative examples are helpful, but I'll revise to make it clear that the are non-exclusive examples, while leaving the exemption for proxies. I'm not sure what to do with this comment; I think it's important that we make it crystal clear who this document is written for and what people are supposed to do with it. It's not long. Revision is in flight.
After discussing this a little more, I have come to realize that most of what you are proposing is covered already - in excruciating detail - in . Maybe the words and framing are different, and it might be less direct than what you propose, but the important concepts exist there. What you propose here takes a small step toward moving that into invariants and I don't think that fits with my conception of the document. The primary function for me is that of a commitment regarding the shape of future versions of QUIC. That's a commitment that the IETF makes, and given what I know about how good we are at keeping those commitments, that's not worth a lot. But if we accept the credibility of that commitment, it has value if it successfully constrains future QUIC versions. Why we do that is in the hope that intermediaries will choose to respect the boundaries we set. So you are right in calling out the fact that this is the line of tape dividing the apartment in two and the effect that has on curtailing the movements of both parties. However, I don't want to say much about intermediaries (though some discussion exists in security considerations). If anything, I would prefer to leave this at something less targeted and more concise. Maybe the following as a new Section 4 "Scope": After that, I think we're into either increasing the scope or taking material from the manageability draft, neither of which I think make this document better.
Good catch on manageability, though that's an Informational draft, and the thread that spawned all this was a desire for normative text. This sounds like an informational purpose to me. Your proposed text is fine. As for my PR, I thought we'd gathered rough consensus that something to that effect was desirable, but I'm not going to lie down in the road over it.
My take on the invariants draft is the same as NAME That is really about what future protocol versions of QUIC need to adhere to. I don't think we should be specifying what we are making available to intermediaries. That is merely a side-effect, and I don't think we should be changing the scope of the document. These bits were not made available so intermediaries could use them. They were made available for the endpoints to pivot around, for the receiver to find the necessary information so that it could decrypt or reject the packet. The bits that are visible to third parties is a consequence, and this consequence is equally useful to intermediaries and sniffing tools. NAME : FWIW, I think the second paragraph in the proposed text is adequate. The first and third explicitly state things that don't really belong in the invariants draft IMO. The only RFC 2119 keywords in this document are related to Version Negotiation packets, and I suspect these requirements might best be in the quic-transport draft. (At the very least, the quic-transport draft should refer to these normative VN requirements hidden in quic-invariants). If there are really no normative requirements on future versions of QUIC with respect to long and short headers, etc, than this really is an informational draft to help middleboxes understand the current IETF consensus about future versions of QUIC. I would much prefer that either: This draft becomes fully normative on future versions of QUIC ("Future versions of QUIC MUST NOT mess with this format..."), or We pull the VN normative text out of -invariants and make this purely Informational. What do others think?

The primary goal of this document is to ensure that it is possible to deploy new versions of QUIC.  By documenting the properties that  <ins> can't change, this document aims to preserve the ability for QUIC endpoints to negotiate changes to any other aspect of the protocol. As a consequence, this also guarantees a minimal amount of information that is made available to entities other than endpoints. Unless specifically prohibited in this document, any aspect of the protocol can change between different versions. </ins> bad-assumptions is a non-exhaustive list of some incorrect assumptions that might be made based on knowledge of QUIC version 1;


the application protocol that QUIC serves. TLS session tickets and address validation tokens are used to <del> carry QUIC configuration information between connections.  These MUST NOT be used to carry application semantics.  The potential for reuse of these tokens means that they require stronger protections against replay. </del>  A server that accepts 0-RTT on a connection incurs a higher cost than accepting a connection without 0-RTT.  This includes higher

The text here was perhaps a little unclear on this point. The point is that these don't carry information from server to client or client to server, they carry information from server (previous) to server (next).
There seems to be a conflict between this assertion in Section 9.2: URL the fact that 4.8 explicitly discusses how application protocols might need to have data embedded in the session ticket. (Also, QUIC doesn't use TLS address validation tokens.) I think this is actually trying to say that receipt of the session ticket MUST NOT cause side-effect beyond setting up the connection, but it's a broader prohibition than that.
I think that it says something else, namely that these are not intended to convey semantic information from client to server (or vice versa). PR inbound.

the application protocol that QUIC serves. TLS session tickets and address validation tokens are used to  <ins> carry QUIC configuration information between connections. Specifically, to enable a server to efficiently recover state that is used in connection establishment and address validation.  These MUST NOT be used to communicate application semantics between endpoints; clients MUST treat them as opaque values.  The potential for reuse of these tokens means that they require stronger protections against replay. </ins> A server that accepts 0-RTT on a connection incurs a higher cost than accepting a connection without 0-RTT.  This includes higher


4.1.5. exchange-summary summarizes the exchange between QUIC and TLS for <del> both client and server.  Each arrow is tagged with the encryption level used for that transmission. </del>  exchange-summary shows the multiple packets that form a single "flight" of messages being processed individually, to show what incoming messages trigger different actions.  New handshake messages <del> are requested after all incoming packets have been processed.  This process might vary depending on how QUIC implementations and the packets they receive are structured. </del>  4.2.

I came back to this today and found that the ordering was inconsistent and not sufficiently clear. Changing this so that all the actions for a single endpoint were grouped seemed to be the best arrangement. All events and actions are as close as possible in the ordering to the preceding event that caused or enabled it. The application data packets are displayed with a different marking, which helps distinguish those that carry CRYPTO frames. The final implied exchange for Get Handshake was removed. This was, I think, intended to imply something about session tickets. Without explanation, it is confusing. This doesn't show HANDSHAKE_DONE, nor do I think that it should, because that is something that the transport does once it gets the Handshake Complete signal.
LGTM, one suggestion

4.1.5. exchange-summary summarizes the exchange between QUIC and TLS for  <ins> both client and server.  Solid arrows indicate packets that carry handshake data; dashed arrows show where application data can be sent.  Each arrow is tagged with the encryption level used for that transmission. </ins> exchange-summary shows the multiple packets that form a single "flight" of messages being processed individually, to show what incoming messages trigger different actions.  New handshake messages  <ins> are requested after incoming packets have been processed.  This process varies based on the structure of endpoint implementations and the order in which packets arrive; this is intended to illustrate the steps involved in a single handshake exchange. </ins> 4.2.


included in a certificate and that the certificate is issued by a trusted entity (see for example RFC2818).  A server MAY request that the client authenticate during the handshake.  A server MAY refuse a connection if the client is unable to authenticate when requested.  The requirements for client

There are a few ways that this can be managed, but it's worth pointing out why, and some things that might help.
Amplification protection (send no more than 3x of receive) on the server side ends up adding an extra round trip in many scenarios than use a large server certificate. Send more in the initial client flight. We already require client Initial packets to be padded to at least 1200 bytes to force them to "pay to play" so to speak, but that's not enough if the server's certificate is larger than ~3K. does a good job of outlining the problem and proposes certificate compression as a possible solution. A simpler solution (IMO) is to recommend clients send more in their initial flight; perhaps two fully padded copies of their Client Hello. This effectively doubles the size of certificate that would fit in the server's first flight. Doubling the number of initial packets may increase congestion at the start of the handshake, but QUIC has already made the decision to send 2 probe packets for recovery, compared to TCP's 1.
How much of this requires specification, as opposed to clients just doing stuff? And how much would relieving this pressure just remove an incentive on servers to have smaller certificates? I mean, if you have a giant certificate, then you get TCP-level performance, maybe that's OK.
According to the data in the blog post, we're talking about ~43% of the handshakes sampled (assuming 1200 byte initial packets). If you make the assumption that operators of these websites do the minimal effort possible when updating to HTTP/3 and continue to have the same certificates, that's 43% of handshakes that get no benefit (during the handshake) for using QUIC. Personally, I think it's something the spec should address with a recommendation.
(I'll invoke the NAME for his thoughts, since he wrote that article.) At a high level, we should be working on reducing the handshake size, for two reasons: reduced packet loss, and reduced network load. Fewer packets in the handshake is generally good. Compression is aligned with this outcome, and it is not a steep hill. Simply inflating the client's hello goes in exactly the opposite direction. I would suggest that simply moving to QUIC without cert compression was not expected to reduce handshake latency. It was always a critical part of gQUIC, and was always considered a part of the equation for realizing QUIC's potential. That is how I read the article -- that to realize QUIC's promise, cert compression is necessary. Perhaps it might be useful to mention this somewhere in the TLS draft?
The thing about the dataset there is that certificate sizes are driven more by the requirements of the current environment. That is, where address validation has already occurred and you are only bound by congestion control limits. There are obviously factors that push people to take advantage of the space available, that primarily being the inclusion of more names. But in the presence of new pressures and new possibilities will create a new incentive structure. ECDSA isn't exactly new, but it leads to much smaller certificate sizes. People deploying QUIC will be able to use ECDSA and to request that their CA do the same for intermediates. That isn't to say that compression isn't worthwhile, but I don't think that it is as critical as Patrick's study might suggest.
Is the resolution here what NAME suggests above, i.e., an editorial addition to -tls
That seems overspecific based on one datapoint and one resolution. A different take on this is to make the observation that within the mechanisms described for QUIC, increasing certificate size can reduce the chances of achieving minimal-possible round-trips. Implementations can use methods to minimize the size of certificates such as ECDSA or compression.
Fair point. But it looks like an editorial change saying "moar handshake data = bad" is what would address the issue?
That seems like a good summary.

included in a certificate and that the certificate is issued by a trusted entity (see for example RFC2818). <ins> Where servers provide certificates for authentication, the size of the certificate chain can consume a large number of bytes. Controlling the size of certificate chains is critical to performance in QUIC as servers are limited to sending 3 bytes for every byte received prior to validating the client address; see Section 8.1 of QUIC-TRANSPORT.  The size of a certificate chain can be managed by limiting the number of names or extensions; using keys with small public key representations, like ECDSA; or by using certificate compression COMPRESS. </ins> A server MAY request that the client authenticate during the handshake.  A server MAY refuse a connection if the client is unable to authenticate when requested.  The requirements for client


defined in long-header.  A Version Negotiation packet is identifiable as such by the Version field, which is set to 0x00000000. <del> The Version Negotiation packet contains a list of Supported Version fields, each identifying a version that the endpoint sending the packet supports.  The Supported Version fields follow the Version field.  A Version Negotiation packet contains no other fields.  An endpoint MUST ignore a packet that contains no Supported Version fields, or a truncated Supported Version. </del>  Version Negotiation packets do not use integrity or confidentiality protection.  Specific QUIC versions define mechanisms to authenticate

As Magnus noted, the description of the first byte is missing, and I also noticed that the Supported Version field was described as following Version, which is wrong.
For -09 in WG LC. Section 6 has a packet header structure with the field: Unused (7) All the other fields are either fixed value or kind of defined earlier. In fact I would argue they represent concepts that are defined in -transport. Thus a second part of this is if -transport needs to be normative reference for the concepts used in this document. But back to Unused: I think this field can take any value on transmission, and should be ignored on reception. Maybe this needs to be noted explicitly in Section 6.
It's very deliberate that Invariants does not normatively depend on Transport. Invariants needs to stand alone, as a description of what versionless QUIC means. Arguably, Transport could normatively depend on Invariants, but it chooses instead to restate the things it depends on and make the reference informative.

defined in long-header.  A Version Negotiation packet is identifiable as such by the Version field, which is set to 0x00000000.  <ins> Only the most significant bit of the first byte of a Version Negotiation packet has any defined value.  The remaining 7 bits, labeled Unused, can be set to any value when sending and MUST be ignored on receipt. After the Source Connection ID field, the Version Negotiation packet contains a list of Supported Version fields, each identifying a version that the endpoint sending the packet supports.  A Version Negotiation packet contains no other fields.  An endpoint MUST ignore a packet that contains no Supported Version fields, or a truncated Supported Version. </ins> Version Negotiation packets do not use integrity or confidentiality protection.  Specific QUIC versions define mechanisms to authenticate


If a max_idle_timeout is specified by either peer in its transport parameters (transport-parameter-definitions), the connection is silently closed and its state is discarded when it remains idle for <del> longer than the minimum of both peers max_idle_timeout values and three times the current Probe Timeout (PTO). </del>  Each endpoint advertises a max_idle_timeout, but the effective value at an endpoint is computed as the minimum of the two advertised a packet.  Restarting this timer when sending a packet ensures that connections are not closed after new activity is initiated.  10.2.1. An endpoint that sends packets close to the effective timeout risks

The text as written implied that the actual timeout period was calculated using: This is silly, as 3PTO is usually smaller than the other two values, and connections would time out too fast. Splitting the text regarding the 3PTO backstop makes this clearer.
Wasn't the intended meaning
I can only speak about my intent, but I did not intend to always add 3PTO to the timeout. The text was clearly more confused than I thought.
I actually wasn't sure what you meant before, but this is what I assumed.

If a max_idle_timeout is specified by either peer in its transport parameters (transport-parameter-definitions), the connection is silently closed and its state is discarded when it remains idle for  <ins> longer than the minimum of both peers max_idle_timeout values. </ins> Each endpoint advertises a max_idle_timeout, but the effective value at an endpoint is computed as the minimum of the two advertised a packet.  Restarting this timer when sending a packet ensures that connections are not closed after new activity is initiated. <ins> To avoid excessively small idle timeout periods, endpoints MUST increase the idle timeout period to be at least three times the current Probe Timeout (PTO). </ins> 10.2.1. An endpoint that sends packets close to the effective timeout risks


The remainder of the Version Negotiation packet is a list of 32-bit versions which the server supports. <del> A Version Negotiation packet cannot be explicitly acknowledged in an ACK frame by a client.  Receiving another Initial packet implicitly acknowledges a Version Negotiation packet. </del>  The Version Negotiation packet does not include the Packet Number and Length fields present in other packets that use the long header form.

This is a left-over from removing version negotiation from the draft.
by a client. Receiving another Initial packet implicitly acknowledges a Version Negotiation packet. This seems like old text from when we removed real VN. I think that you just need to say that no ACK is required because you only send it in response to Initial.
LGTM

The remainder of the Version Negotiation packet is a list of 32-bit versions which the server supports.  <ins> A Version Negotiation packet is not acknowledged.  It is only sent in response to a packet that indicates an unsupported version; see server-pkt-handling. </ins> The Version Negotiation packet does not include the Packet Number and Length fields present in other packets that use the long header form.


or Handshake packets. Section 4 of QUIC-TLS provides more detail about these restrictions. <del> Note that all frames can appear in 1-RTT packets. </del>  The "Spec" column in frame-types summarizes any special rules governing the processing or generation of the frame type, as

error of type FRAMEENCODINGERROR. What about a frame of an impermissible type for this key space?
URL
This seems to only apply to 0-RTT, but there are lots of frames which may not appear in Initial

or Handshake packets. Section 4 of QUIC-TLS provides more detail about these restrictions.  <ins> Note that all frames can appear in 1-RTT packets.  An endpoint MUST treat receipt of a frame in a packet type that is not permitted as a connection error of type PROTOCOL_VIOLATION. </ins> The "Spec" column in frame-types summarizes any special rules governing the processing or generation of the frame type, as