jiebi/TextFlow huggingface dataset:
Original text:
If the Destination Connection ID is zero length and the packet matches the address/port tuple of a connection where the host did not require connection IDs, QUIC processes the packet as part of that <del> connection.  Endpoints MUST drop packets with zero-length Destination Connection ID fields if they do not correspond to a single connection. </del>  Endpoints can send a Stateless Reset (stateless-reset) for any packets that cannot be attributed to an existing connection.  A

Reviewer comments:
How could this happen? The recipient knows if a given tuple is unique, so it shouldn't issue zero-length DCIDs for that tuple.
Yeah, it is more like recipients MUST not issue 0-length CID's in that case. And MUST drop non-issued CID's.
I remember why was added. If you had one connection on those addresses, time passes and a NAT rebinding moves another connection to that same path, then you get problems. That a nonsensical situation and better addressed as suggested.

Revised text:
If the Destination Connection ID is zero length and the packet matches the address/port tuple of a connection where the host did not require connection IDs, QUIC processes the packet as part of that  <ins> connection.  Endpoints SHOULD either reject connection attempts that use the same addresses as existing connections, or use a non-zero- length Destination Connection ID so that packets can be correctly attributed to connections. </ins> Endpoints can send a Stateless Reset (stateless-reset) for any packets that cannot be attributed to an existing connection.  A
Original text:
On receiving a PATH_CHALLENGE frame, an endpoint MUST respond immediately by echoing the data contained in the PATH_CHALLENGE frame <del> in a PATH_RESPONSE frame.  However, because a PATH_CHALLENGE might be sent from a spoofed address, an endpoint MUST limit the rate at which it sends PATH_RESPONSE frames and MAY silently discard PATH_CHALLENGE frames that would cause it to respond at a higher rate. </del>  To ensure that packets can be both sent to and received from the peer, the PATH_RESPONSE MUST be sent on the same path as the

Reviewer comments:
Implementations can do this anyway, so we're not getting much from the recommendation. And we already have good limits on what can be sent (including PATH_RESPONSE) in the migration section.
This can lead to amplification attack if not careful.
NAME how can this lead to amplification?
If an endpoint seeing a challenge uses the opportunity to discover if its preferred MTU is supported by padding the response (as opposed to the challenge) even if the challenge packet is small. Since this might fail, it like will also send a small response after a delay or after a new challenge if it doesn't get an ACK before that. A defence could be to ensure that challenges are no larger than, say twice, response.
An endpoint may also optimistically bundle all kinds of other data in a response. Even with 1200 bytes, this can be much larger than a small challenge packet without considering PMTU discovery at all.
I think I raised this issue quite a while ago this is the reason the limit was introduced, although I didn't formulate the exact counter measure.
The counter measure we have against amplification is the initial congestion window. We won't send more than that. That's higher than the x3 we have during the handshake, but I think that's a reasonable balance, considering that the attacker in this context has to spend a considerable amount of effort. Yes, this is a policy question, but I'm happy with it. (Though we should probably highlight this when asking for review.)
It's pretty hard to understand what the normative force of this is, given that it doesn't explain what the limit is. I think there's actually a simple rule we should propose, which is one PATH_CHALLENGE frame per packet (with others to be ignored). Given that we require duplicate suppression at the packet level, that will have an amplification factor of 1:1, which you can get by a variety of other mechanisms.
The relevant existing guideline is the 3x limit we have on handshake amplification. Given that CHALLENGE/RESPONSE doesn't inherently include any amplification other than what might result from different connection ID lengths on packets, I don't think that we need to do much special. That is, the text in 9.3.1 is fine, even if the limits are different. I'm OK with striking everything from "However" onward here.

Revised text:
On receiving a PATH_CHALLENGE frame, an endpoint MUST respond immediately by echoing the data contained in the PATH_CHALLENGE frame  <ins> in a PATH_RESPONSE frame. </ins> To ensure that packets can be both sent to and received from the peer, the PATH_RESPONSE MUST be sent on the same path as the
Original text:
To limit ACK Blocks to those that have not yet been received by the sender, the receiver SHOULD track which ACK frames have been <del> acknowledged by its peer.  Once an ACK frame has been acknowledged, the packets it acknowledges SHOULD NOT be acknowledged again. </del>  Because ACK frames are not sent in response to ACK-only packets, a receiver that is only sending ACK frames will only receive

Reviewer comments:
Thanks everyone, this is much better.
From NAME I think that the advice here is that ranges are dropped when all ACKs for all packets in that range have been acknowledged. Or something along those lines. Maybe: Though that seems clumsy. Better words would be appreciated.
Maybe "Endpoints SHOULD not acknowledge packets for which it has already received acknowledgement of acknowledgements, except where this would create unnecessary gaps in the encoded ACK frame." Not ideal, I know/
I think this is connected to in an interesting way. The question that arises is if one MUST include all ACK state between highest received, and the lower PN that needs to be ACKed (as it is newly arrived due to reordering). An alternative would be to explicitly allow GAPs for packets that has been received and where the reception's ACKs has been ACKed. But, I guess that results in interesting bookkeeping chores in the implementations.
Agreed the wording is too strong. Take a look at PR

Revised text:
To limit ACK Blocks to those that have not yet been received by the sender, the receiver SHOULD track which ACK frames have been  <ins> acknowledged.  The receiver SHOULD exclude already acknowledged packets from future ACK frames whenever these packets would unnecessarily contribute to the ACK frame size. </ins> Because ACK frames are not sent in response to ACK-only packets, a receiver that is only sending ACK frames will only receive
Original text:
QUIC connections are established as described in QUIC-TRANSPORT. During connection establishment, HTTP/3 support is indicated by <del> selecting the ALPN token "hq" in the TLS handshake.  Support for </del>  other application-layer protocols MAY be offered in the same handshake.

Reviewer comments:
Section 2.3, paragraph 2 still uses "hq"
Good spot, PR fixes this
Whoops!

Revised text:
QUIC connections are established as described in QUIC-TRANSPORT. During connection establishment, HTTP/3 support is indicated by  <ins> selecting the ALPN token "h3" in the TLS handshake.  Support for </ins> other application-layer protocols MAY be offered in the same handshake.
Original text:
ALTSVC frame (ALTSVC), using the ALPN token defined in connection- establishment. <del> For example, an origin could indicate in an HTTP/1.1 or HTTP/2 response that HTTP/3 was available on UDP port 50781 at the same hostname by including the following header field in any response: </del>  On receipt of an Alt-Svc record indicating HTTP/3 support, a client MAY attempt to establish a QUIC connection to the indicated host and

Reviewer comments:
HTTP response headers are common across HTTP/1.1, HTTP/2 and HTTP/3. There seems no need to be so precise on what version of the protocol returns the example header.

Revised text:
ALTSVC frame (ALTSVC), using the ALPN 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 following header field: </ins> On receipt of an Alt-Svc record indicating HTTP/3 support, a client MAY attempt to establish a QUIC connection to the indicated host and
Original text:
10.4.1. <del> An endpoint detects a potential stateless reset when a packet with a short header either cannot be decrypted or is marked as a duplicate packet.  The endpoint then compares the last 16 bytes of the packet with the Stateless Reset Token provided by its peer, either in a </del>  NEW_CONNECTION_ID frame or the server's transport parameters.  If these values are identical, the endpoint MUST enter the draining period and not send any further packets on this connection.  If the

Reviewer comments:
If connection for incoming packet cannot be found, check whether this is a stateless reset packet.
states: This only works for endpoints whose SCID is zero length. If SCID is not zero length, the connection corresponding to the stateless reset packet will not be found. This latter case should be included in the stateless reset detection algorithm.
OK with the requested changes.

Revised text:
10.4.1.  <ins> An endpoint detects a potential stateless reset when a incoming packet with a short header either cannot be associated with a connection, cannot be decrypted, or is marked as a duplicate packet. The endpoint then compares the last 16 bytes of the packet with the Stateless Reset Token provided by its peer, either in a </ins> NEW_CONNECTION_ID frame or the server's transport parameters.  If these values are identical, the endpoint MUST enter the draining period and not send any further packets on this connection.  If the
Original text:
transmitted on a stream.  For a stream that is reset, the final offset is carried explicitly in a RESET_STREAM frame.  Otherwise, the final offset is the offset of the end of the data carried in a STREAM <del> frame marked with a FIN flag, or 0 in the case of incoming unidirectional streams. </del>  An endpoint will know the final offset for a stream when the receiving part of the stream enters the "Size Known" or "Reset Recvd"

Reviewer comments:
I think the text is a leftover from time before we introduced STOP_SENDING.
There was an earlier draft where RST could be used for both locally and peer initiated streams. Not sure if that is relevant here.

Revised text:
transmitted on a stream.  For a stream that is reset, the final offset is carried explicitly in a RESET_STREAM frame.  Otherwise, the final offset is the offset of the end of the data carried in a STREAM  <ins> frame marked with a FIN flag. </ins> An endpoint will know the final offset for a stream when the receiving part of the stream enters the "Size Known" or "Reset Recvd"
Original text:
This parameter is an integer value specifying the initial flow control limit for unidirectional streams.  This limit applies to <del> newly created bidirectional streams opened by the endpoint that </del>  receives the transport parameter.  In client transport parameters, this applies to streams with an identifier with the least significant two bits set to 0x3; in server transport parameters,

Reviewer comments:
Quoted from draft 17, value specifying the initial flow control limit for unidirectional streams. This limit applies to newly created bidirectional streams It should be - This limit applies to newly created unidirectional...

Revised text:
This parameter is an integer value specifying the initial flow control limit for unidirectional streams.  This limit applies to  <ins> newly created unidirectional streams opened by the endpoint that </ins> receives the transport parameter.  In client transport parameters, this applies to streams with an identifier with the least significant two bits set to 0x3; in server transport parameters,
Original text:
4.5. In order to be usable for 0-RTT, TLS MUST provide a NewSessionTicket <del> message that contains the "max_early_data" extension with the value 0xffffffff; the amount of data which the client can send in 0-RTT is controlled by the "initial_max_data" transport parameter supplied by the server.  A client MUST treat receipt of a NewSessionTicket that contains a "max_early_data" extension with any other value as a connection error of type PROTOCOL_VIOLATION. </del>  Early data within the TLS connection MUST NOT be used.  As it is for other TLS application data, a server MUST treat receiving early data

Reviewer comments:
What exists is "earlydata" extension and its "maxearlydatasize" field.

Revised text:
4.5. In order to be usable for 0-RTT, TLS MUST provide a NewSessionTicket  <ins> message that contains the "early_data" extension with a max_early_data_size of 0xffffffff; the amount of data which the client can send in 0-RTT is controlled by the "initial_max_data" transport parameter supplied by the server.  A client MUST treat receipt of a NewSessionTicket that contains an "early_data" extension with any other value as a connection error of type PROTOCOL_VIOLATION. </ins> Early data within the TLS connection MUST NOT be used.  As it is for other TLS application data, a server MUST treat receiving early data
Original text:
identifies the frame.  These frames are explained in more detail in frame-formats. <del> All QUIC frames are idempotent.  That is, a valid frame does not cause undesirable side effects or errors when received more than once. </del>  The Frame Type field uses a variable length integer encoding (see integer-encoding) with one exception.  To ensure simple and efficient

Reviewer comments:
Is this just a statement about this spec or a normative requirement on future specs?
It is not an invariant.
There's more to requirements on future specs than invariants.
It's a statement about the current version, but it would presumptively apply to extensions to the current version that don't redefine the base spec.
Perhaps it'd be better to use to avoid confusion like this.

Revised text:
identifies the frame.  These frames are explained in more detail in frame-formats.  <ins> All QUIC frames are idempotent in this version of QUIC.  That is, a valid frame does not cause undesirable side effects or errors when received more than once. </ins> The Frame Type field uses a variable length integer encoding (see integer-encoding) with one exception.  To ensure simple and efficient
Original text:
4.2.6. The PUSH_PROMISE frame (type=0x05) is used to carry a promised <del> request header set from server to client, as in HTTP/2. </del>  The payload consists of: the client has advertised or a Push ID which has already been promised as a connection error of type HTTP_MALFORMED_FRAME.  See server-push for a description of the overall server push mechanism.

Reviewer comments:
All other frame types in section 4 explicitly call out which stream types are allowed. For example DATA: If a DATA frame is received on either control stream, the recipient MUST respond with a connection error (Section 8) of type HTTPWRONGSTREAM.
FWIW this is explained in section 5. But I agree that conistency in the frame descriptions could help.

Revised text:
4.2.6. The PUSH_PROMISE frame (type=0x05) is used to carry a promised  <ins> request header set from server to client on a request stream, as in HTTP/2. </ins> The payload consists of: the client has advertised or a Push ID which has already been promised as a connection error of type HTTP_MALFORMED_FRAME. <ins> If a PUSH_PROMISE frame is received on either control stream, the recipient MUST respond with a connection error (errors) of type HTTP_WRONG_STREAM. </ins> See server-push for a description of the overall server push mechanism.
Original text:
than the server's advertised idle timeout, and SHOULD do so if approaching the idle timeout. <del> HTTP clients are expected to use QUIC PING frames to keep connections open while there are responses outstanding for requests or server pushes.  If the client is not expecting a response from the server, allowing an idle connection to time out is preferred over expending effort maintaining a connection that might not be needed.  A gateway MAY use PING to maintain connections in anticipation of need rather than incur the latency cost of connection establishment to servers. Servers SHOULD NOT use PING frames to keep a connection open. </del>  6.2.

Reviewer comments:
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?
In , the direction of the discussion is that PING frames are an application-layer concept that won't necessarily be directly under the application-layer's control. The HTTP draft currently says: This should be reworded in terms of requesting the transport stack to keep the connection from idling out, rather than directly discussing PING frames.
Or maybe we just need to kinds of PING?
Gah! Not more types of PING please!
KEEPTHECARRUNNING frame (ID=0xAF)

Revised text:
than the server's advertised idle timeout, and SHOULD do so if approaching the idle timeout.  <ins> HTTP clients are expected to request that the transport keep connections open while there are responses outstanding for requests 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 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 NOT actively keep connections open. </ins> 6.2.
Original text:
A server might receive a packet addressed to its preferred IP address at any time after it accepts a connection.  If this packet contains a PATH_CHALLENGE frame, the server sends a PATH_RESPONSE frame as per <del> migrate-validate.  The server MAY send other non-probing frames from its preferred address, but MUST continue sending all probing packets from its original IP address. </del>  <del> The server SHOULD also initiate path validation of the client using its preferred address and the address from which it received the client probe.  This helps to guard against spurious migration </del>  initiated by an attacker. Once the server has completed its path validation and has received a

Reviewer comments:
Editorial because it now says what we originally thought it said, but design because it is changing normative language. Does not interact with .
The following text is kind of hard to track: I'm not really following what's going on here. The server knows that it has two addresses and it wants to use its preferred address. Why does it have to probe from its preferred address. Also, I don't understand how these two paragraphs work together. The first one says you have to send probing packets from your original address but the second paragraph tells you to probe from the preferrd address.
You're right, that last restriction in the first paragraph looks backwards. IIRC, it's supposed to be a reiteration of the fact that the client decides when to actually cut over, so the server shouldn't be sending non-probing packets from the preferred address until the client starts sending them there. This is section 9.6.2 of Transport.
I think that the first paragraph is just missing "... until it receives a non-probing packet from the client at its preferred address." Then maybe a simple: "The server MUST probe on the path toward its preferred address before sending non-probing packets."

Revised text:
A server might receive a packet addressed to its preferred IP address at any time after it accepts a connection.  If this packet contains a PATH_CHALLENGE frame, the server sends a PATH_RESPONSE frame as per  <ins> migrate-validate.  The server MUST send other non-probing frames from its original address until it receives a non-probing packet from the client at its preferred address and until the server has validated the new path. </ins>  <ins> The server MUST probe on the path toward the client from its preferred address.  This helps to guard against spurious migration </ins> initiated by an attacker. Once the server has completed its path validation and has received a
Original text:
number space.  Separate packet number spaces ensures acknowledgement of packets sent with one level of encryption will not cause spurious retransmission of packets sent with a different encryption level. <del> Congestion control and RTT measurement are unified across packet number spaces. </del>  3.1.2. 5. <del> RTT is calculated when an ACK frame arrives by computing the difference between the current time and the time the largest acked packet was sent.  An RTT sample MUST NOT be taken for a packet that is not newly acknowledged or not ack-eliciting. </del>  When RTT is calculated, the ack delay field from the ACK frame SHOULD be limited to the max_ack_delay specified by the peer.  Limiting QUIC senders use both ack information and timeouts to detect lost packets, and this section provides a description of these algorithms. <del> Estimating the network round-trip time (RTT) is critical to these algorithms and is described first. </del> If a packet is lost, the QUIC transport needs to recover from that loss, such as by retransmitting the data, sending an updated frame,

Reviewer comments:
Explicitly state that round trip time is abbreviated as RTT
In the recovery draft, RTT is briefly spelled out in section 5 but is used in several earlier sections. SRTT and PTO are not explained at all, it seems. TLP is spelled out. RTO has a section of its own but it referenced before that. The recovery doc cannot be a tutorial on transmission theory, but it would be helpful to list the key acronyms and possibly reference an RFC with more details. There are already sections summarising key variables in pseudocode. There are references at the end, but the reader would have to go through them all.
Yes, thanks for the note. I'm planning to do a cleanup of that doc soon.
I fixed defined RTT earlier in .

Revised text:
number space.  Separate packet number spaces ensures acknowledgement of packets sent with one level of encryption will not cause spurious retransmission of packets sent with a different encryption level.  <ins> Congestion control and round-trip time (RTT) measurement are unified across packet number spaces. </ins> 3.1.2. 5.  <ins> Round-trip time (RTT) is calculated when an ACK frame arrives by computing the difference between the current time and the time the largest acked packet was sent.  An RTT sample MUST NOT be taken for a packet that is not newly acknowledged or not ack-eliciting. </ins> When RTT is calculated, the ack delay field from the ACK frame SHOULD be limited to the max_ack_delay specified by the peer.  Limiting QUIC senders use both ack information and timeouts to detect lost packets, and this section provides a description of these algorithms.  If a packet is lost, the QUIC transport needs to recover from that loss, such as by retransmitting the data, sending an updated frame,