jiebi/TextFlow huggingface dataset:
Original text:
packet protection. A client only receives acknowledgments for its 0-RTT packets once the <del> handshake is complete. </del>  A client MUST NOT send 0-RTT packets once it starts processing 1-RTT packets from the server.  This means that 0-RTT packets cannot

Reviewer comments:
Specify that when the spec says that a "client only receives acknowledgments for its 0-RTT packets once the handshake is complete", it means "as defined in the Handshake Complete section of {{QUIC-TLS}}.".
is complete. Consequently, a server might expect 0-RTT packets to start with a However, this is not necessarily strictly true, because you might have the ACKs in 0.5RTT. Now you might say that the TLS stack reports the handshake as complete as soon as it receives Finished but that's an implementation detail
I think that this is true. The server can send before then, but we require that the client not install 1-RTT keys until it considers the handshake complete.
That's not entirely true. It's the server that needs to hold back keys (namely, the 1-RTT read key) until the handshake completes. The client can use keys as soon as they become available.
I think NAME is correct in sense that the following three events happen at the same moment on the client side: handshake is declared complete TLS stack provides the 1-RTT read and write keys TLS stack provides ClientFinished
Martin is correct. There are two different forms of handshake completion: complete when 1rtt can be sent and received, confirmed when the peer is known to be complete. The client cannot receive 0rtt acks before installing 1rtt keys, hence before hanshake is complete.
We've generally used section numbers for this.

Revised text:
packet protection. A client only receives acknowledgments for its 0-RTT packets once the  <ins> handshake is complete, as defined Section 4.1.1 of QUIC-TLS. </ins> A client MUST NOT send 0-RTT packets once it starts processing 1-RTT packets from the server.  This means that 0-RTT packets cannot
Original text:
The encoded packet number is protected as described in Section 5.4 of QUIC-TLS. <del> The sender MUST use a packet number size able to represent more than </del>  twice as large a range than the difference between the largest acknowledged packet and packet number being sent.  A peer receiving the packet will then correctly decode the packet number, unless the packet protection. A client only receives acknowledgments for its 0-RTT packets once the <del> handshake is complete.  Consequently, a server might expect 0-RTT packets to start with a packet number of 0.  Therefore, in determining the length of the packet number encoding for 0-RTT packets, a client MUST assume that all packets up to the current packet number are in flight, starting from a packet number of 0. Thus, 0-RTT packets could need to use a longer packet number encoding. </del>  A client MUST NOT send 0-RTT packets once it starts processing 1-RTT packets from the server.  This means that 0-RTT packets cannot

Reviewer comments:
I noticed the 0-RTT specific text in and thought a general clarification would be better. Conveniently, I don't think anyone has gotten this wrong in their implementation.
Thanks Ian, this is much clearer.

Revised text:
The encoded packet number is protected as described in Section 5.4 of QUIC-TLS.  <ins> Prior to receiving an acknowledgement for a packet number space, the full packet number MUST be included. After an acknowledgement is received for a packet number space, the sender MUST use a packet number size able to represent more than </ins> twice as large a range than the difference between the largest acknowledged packet and packet number being sent.  A peer receiving the packet will then correctly decode the packet number, unless the packet protection. A client only receives acknowledgments for its 0-RTT packets once the  <ins> handshake is complete. </ins> A client MUST NOT send 0-RTT packets once it starts processing 1-RTT packets from the server.  This means that 0-RTT packets cannot
Original text:
MUST NOT consider these streams to have any meaning upon receipt. The payload and length of the stream are selected in any manner the <del> implementation chooses.  Implementations MAY terminate these streams cleanly, or MAY abruptly terminate them.  When terminating abruptly, the error code H3_NO_ERROR or a reserved error code (http-error- codes) SHOULD be used. </del>  7.

Reviewer comments:
I totally misread this passage, so let's make it more emphatic which side of the stream we're talking about.
In Section 6.2.3, we recommend the following about the reserved unidirectional stream types: However, this has a fatal flaw -- it recommends special handling for the grease types, which is precisely the behavior we're trying to disincent with grease. Instead, I think we should move the recommendation to use reserved error codes to the guidance on what to do with unknown stream types, which is currently: This has the same net effect on the grease streams. The change in behavior is on actual unknown-but-real stream types, which will now get grease error codes in response.
+1 lets do this (as an individual)
Actually, scratch that -- it's a misreading. This is a statement about how the sender of the stream should close them, not about behavior on receipt at all. I'll take this as editorial to emphasize that this is purely about how to send them.

Revised text:
MUST NOT consider these streams to have any meaning upon receipt. The payload and length of the stream are selected in any manner the  <ins> sending implementation chooses.  When sending a reserved stream type, the implementation MAY either terminate the stream cleanly or reset it.  When resetting the stream, either the H3_NO_ERROR error code or a reserved error code (http-error-codes) SHOULD be used. </ins> 7.
Original text:
A variable-length integer error code which indicates the reason for closing this connection.  A CONNECTION_CLOSE frame of type <del> 0x1c uses codes from the space defined in error-codes.  A CONNECTION_CLOSE frame of type 0x1d uses codes from the </del>  application protocol error code space; see app-error-codes. A variable-length integer encoding the type of frame that 20. <del> QUIC error codes are 62-bit unsigned integers. </del>  This section lists the defined QUIC transport error codes that may be <del> used in a CONNECTION_CLOSE frame.  These errors apply to the entire connection. </del>  An endpoint uses this with CONNECTION_CLOSE to signal that the connection is being closed abruptly in the absence of any error. Finally, generic errors are provided for conditions where implementations are unable or unwilling to use more specific codes. <del> 20.1. </del>  <del> Application protocol error codes are 62-bit unsigned integers, but the management of application error codes is left to application </del>  protocols.  Application protocol error codes are used for the RESET_STREAM frame (frame-reset-stream), the STOP_SENDING frame (frame-stop-sending), and the CONNECTION_CLOSE frame with a type of

Reviewer comments:
The current structure is incorrect, because application error codes is a subsection of transport error codes, despite application error codes being disjoint from transport error codes.
Wonderful. Thank you.

Revised text:
A variable-length integer error code which indicates the reason for closing this connection.  A CONNECTION_CLOSE frame of type  <ins> 0x1c uses codes from the space defined in transport-error-codes. A CONNECTION_CLOSE frame of type 0x1d uses codes from the </ins> application protocol error code space; see app-error-codes. A variable-length integer encoding the type of frame that 20.  <ins> QUIC transport error codes and application error codes are 62-bit unsigned integers. 20.1. </ins> This section lists the defined QUIC transport error codes that may be  <ins> used in a CONNECTION_CLOSE frame with a type of 0x1c.  These errors apply to the entire connection. </ins> An endpoint uses this with CONNECTION_CLOSE to signal that the connection is being closed abruptly in the absence of any error. Finally, generic errors are provided for conditions where implementations are unable or unwilling to use more specific codes.  <ins> 20.2. </ins>  <ins> The management of application error codes is left to application </ins> protocols.  Application protocol error codes are used for the RESET_STREAM frame (frame-reset-stream), the STOP_SENDING frame (frame-stop-sending), and the CONNECTION_CLOSE frame with a type of
Original text:
8. QUIC allows the application to abruptly terminate (reset) individual <del> streams or the entire connection when an error is encountered.  These are referred to as "stream errors" or "connection errors" and are described in more detail in QUIC-TRANSPORT. </del>  An endpoint MAY choose to treat a stream error as a connection error under certain circumstances.  Implementations need to consider the

Reviewer comments:
The application may reset a stream, for example, when a browser tab is closed or when the pushed resource is found in cache. It might close the connection when the application is closed. These are not errors per se, even though the term "stream error" and "connection error" is used for these events, and they have an associated "error code".

Revised text:
8. QUIC allows the application to abruptly terminate (reset) individual  <ins> streams or the entire connection; see Sections 2.4 and 5.3 of QUIC- TRANSPORT.  These are referred to as "stream errors" or "connection errors" (see Section 11 of QUIC-TRANSPORT) and have associated error codes, but do not necessarily indicate a problem with the connection or either implementation.  For example, a stream can be reset if the requested resource is no longer needed. </ins> An endpoint MAY choose to treat a stream error as a connection error under certain circumstances.  Implementations need to consider the
Original text:
10.1.1. An endpoint that sends packets close to the effective timeout risks <del> having them be discarded at the peer, since the peer might enter its draining state before these packets arrive. </del>  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 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 <del> frame periodically to defer an idle timeout; see frame-ping. </del>  Application protocols that use QUIC SHOULD provide guidance on when deferring an idle timeout is appropriate.  Unnecessary sending of

Reviewer comments:
Idle timeout doesn't enter the draining period. Sending PING will reset both idle timeouts for both endpoints.
if it is expecting response data, but does not have or is unable to send application data. However, you can't necessarily reset your own idle_timeout that way because it only is reset when you haven't already sent an ack-eliciting packet after the last received packet. If this is about resetting the peer, then maybe editorial. If it is about resetting yourself, then this may be design.
This is both idle timeouts. The idea behind the rules regarding the local reset of the idle timer is that if you send an ack-eliciting packet, you will get an acknowledgment. You are required to send probes until you do. So you only reset the timeout on the first.
says that after the idle timeout expires, "the connection is silently closed and its state is discarded." However, 10.2.1 says that the peer "might enter its draining state." Based on 10.2, I would not expect there to be a draining state; the connection is simply gone, and you would get a stateless reset. Is the draining state used after the endpoints time out, or not?
I need to find the issue, but we explicitly decided to not drain after idle timeout.
resolved this.
Couple of nits, but LGTM.

Revised text:
10.1.1. An endpoint that sends packets close to the effective timeout risks  <ins> having them be discarded at the peer, since the idle timeout period might have expired at the peer before these packets arrive. </ins> 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 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  <ins> frame (frame-ping) periodically, which will cause the peer to restart its idle timeout period.  Sending a packet containing a PING frame restarts the idle timeout for this endpoint also if this is the first ack-eliciting packet sent since receiving a packet.  Sending a PING frame causes the peer to respond with an acknowledgment, which also restarts the idle timeout for the endpoint. </ins> Application protocols that use QUIC SHOULD provide guidance on when deferring an idle timeout is appropriate.  Unnecessary sending of
Original text:
Frame types that were used in HTTP/2 where there is no corresponding HTTP/3 frame have also been reserved (iana-frames).  These frame <del> types MUST NOT be sent, and receipt MAY be treated as an error of type H3_FRAME_UNEXPECTED. </del>  8.

Reviewer comments:
We currently say: This text has two failings: It doesn't specify whether the error is a stream error or a connection error In , it was argued that this violation is easily detected, and perhaps warrants a "MUST error" instead of a "MAY error"
+1 to both changes from my perspective.
This sounds like a design issue. Since this spins off from URL and URL I'm going to assume from past discussion that there is sufficient interest in discussing this.
MUST respond with a connection error SGTM. Frames are hop-by-hop (compared to HTTP messages being end-to-end), therefore we can enforce this.
Thanks, NAME This had shades of the tunneling discussion before, and I wasn't sure on which side of that fence you'd land.
NAME Thank you for checking. As stated above, I think we can be strict regarding HTTP frames (especially the types), even though I tend to think that we need to be lax about HTTP messages (and how they are terminated).

Revised text:
Frame types that were used in HTTP/2 where there is no corresponding HTTP/3 frame have also been reserved (iana-frames).  These frame  <ins> types MUST NOT be sent, and their receipt MUST be treated as a connection error of type H3_FRAME_UNEXPECTED. </ins> 8.
Original text:
CONNECTION_CLOSE frames sent in multiple packet types can be coalesced into a single UDP datagram; see packet-coalesce. <del> An endpoint might send a CONNECTION_CLOSE frame in an Initial packet or in response to unauthenticated information received in Initial or Handshake packets.  Such an immediate close might expose legitimate connections to a denial of service.  QUIC does not include defensive measures for on-path attacks during the handshake; see handshake-dos. However, at the cost of reducing feedback about errors for legitimate peers, some forms of denial of service can be made more difficult for an attacker if endpoints discard illegal packets rather than terminating a connection with CONNECTION_CLOSE.  For this reason, endpoints MAY discard packets rather than immediately close if errors are detected in packets that lack authentication. </del>  An endpoint that has not established state, such as a server that detects an error in an Initial packet, does not enter the closing

Reviewer comments:
This sentence structure was unnecessarily byzantine.
is hard to read. [A D] [A D]] [A D]] ...

Revised text:
CONNECTION_CLOSE frames sent in multiple packet types can be coalesced into a single UDP datagram; see packet-coalesce.  <ins> An endpoint can send a CONNECTION_CLOSE frame in an Initial packet. This might be in response to unauthenticated information received in Initial or Handshake packets.  Such an immediate close might expose legitimate connections to a denial of service.  QUIC does not include defensive measures for on-path attacks during the handshake; see handshake-dos.  However, at the cost of reducing feedback about errors for legitimate peers, some forms of denial of service can be made more difficult for an attacker if endpoints discard illegal packets rather than terminating a connection with CONNECTION_CLOSE. For this reason, endpoints MAY discard packets rather than immediately close if errors are detected in packets that lack authentication. </ins> An endpoint that has not established state, such as a server that detects an error in an Initial packet, does not enter the closing
Original text:
An endpoint MUST NOT send a packet if it would cause bytes_in_flight (see vars-of-interest) to be larger than the congestion window, <del> unless the packet is sent on a PTO timer expiration; see pto. </del>  7.1.

Reviewer comments:
We may want to revert this once lands
~ still allows you to reduce the cwnd on entering recovery, so I think this text is still good.~ Now that I've seen your changes to , reverting this makes sense.
It might pay to reconcile: {{vars-of-interest}}) to be larger than the congestion window, unless the packet is sent on a PTO timer expiration; see {{pto}}. And now exceeds the recently reduced congestion window. Now, you might implement the latter using PTO machinery, but that text doesn't really suggest that in any way.
Where does this second sentence come from? I'm pretty sure I haven't implemented anything like this in quic-go. Should I?
That sentence is the the definition of the . We haven't implemented that either, and I was wondering if it truly helps.
For TCP this second case if important because as long as you don't retransmit the lost packet you will not get any ACK that acknowledges new data. I guess we don't need that for QUIC.
The second sentence was added later in , and the MUST wasn't updated, so I'll fix that. Chromium currently implements PRR(RFC6937), which is a more complex variant of this which is designed to keep the ACK clock going. I thought we discussed adding an informative reference to PRR when we added this text, and I'm not sure why we didn't.
seems to be the wrong issue you are pointed to...
Good catch, it's
Thanks. Simple :)

Revised text:
An endpoint MUST NOT send a packet if it would cause bytes_in_flight (see vars-of-interest) to be larger than the congestion window,  <ins> unless the packet is sent on a PTO timer expiration (see pto) or when entering recovery (see recovery-period). </ins> 7.1.
Original text:
A decoder can limit the amount of state memory used for blocked streams by setting an appropriate value for the maximum number of blocked streams.  In HTTP/3, this is realized by setting an <del> appropriate value for the QPACK_BLOCKED_STREAMS parameter.  An encoder can limit the amount of state memory by only using as many blocked streams as it wishes to support; no signaling to the decoder is required. </del>  The amount of temporary memory consumed by an encoder or decoder can be limited by processing header fields sequentially.  A decoder

Reviewer comments:
Per discussion on Slack, expanding this discussion in the Security Considerations to be more accurate. Editorial, since these are purely statements about the properties of the design.
This is true, but this is also obvious, at least once you start implementing the encoder. Too, there is the natural limit on dynamic references: it is the function of the product of the number of allowed streams and the number of entries in the dynamic table (which itself is a function of the table size). I am concerned that this new verbiage puts the wrong thought into the head of the implementer; we should not encourage this. Limiting the number of dynamic table references (done out of memory conservation zeal) affects compression performance directly -- it worsens it. Perhaps we can tack on the following sentence to the end of the paragraph:
I'm OK with that, though I would qualify with "compression performance", as performance has other dimensions that the extra state might impinge upon.
Another thing to note is that sometimes dynamic table references do not have to have their own objects in the encoder. For examples, they are in ls-qpack. (Everyone reading this in 2022: you're welcome)
Yeah, compression performance qualification is a good suggestion.

Revised text:
A decoder can limit the amount of state memory used for blocked streams by setting an appropriate value for the maximum number of blocked streams.  In HTTP/3, this is realized by setting an  <ins> appropriate value for the QPACK_BLOCKED_STREAMS parameter.  Streams which risk becoming blocked consume no additional state memory on the encoder. An encoder allocates memory to track all dynamic table references in unacknowledged field sections.  An implementation can directly limit the amount of state memory by only using as many references to the dynamic table as it wishes to track; no signaling to the decoder is required.  However, limiting references to the dynamic table will reduce compression effectiveness. </ins> The amount of temporary memory consumed by an encoder or decoder can be limited by processing header fields sequentially.  A decoder
Original text:
receiver's buffer capacity for the connection, by limiting the total bytes of stream data sent in STREAM frames on all streams. <del> Senders MUST not send data in excess of either limit. </del>  A receiver sets initial limits for all streams by sending transport parameters during the handshake (transport-parameters).  A receiver

Reviewer comments:
Noticed while reading text for a different issue; this appears to be the only instance of this construction in the documents.

Revised text:
receiver's buffer capacity for the connection, by limiting the total bytes of stream data sent in STREAM frames on all streams.  <ins> Senders MUST NOT send data in excess of either limit. </ins> A receiver sets initial limits for all streams by sending transport parameters during the handshake (transport-parameters).  A receiver
Original text:
MAX_DATA frame, which indicates the maximum of the sum of the absolute byte offsets of all streams.  A receiver maintains a cumulative sum of bytes received on all streams, which is used to <del> check for flow control violations.  A receiver might use a sum of bytes consumed on all streams to determine the maximum data limit to be advertised. </del>  Once a receiver advertises a limit for the connection or a stream, it MAY advertise a smaller limit, but this has no effect.

Reviewer comments:
(Broken out of .) >A receiver maintains a cumulative sum of It would have helped me, had this explained what was intended by “control violations” - I think it means to detect when the sender sends more than permitted by the flow control limit. I think the control part comes in a later sentence? (Is this measured against the largest advertised offset, or the current offset? … given what is written about reducing the advertised value?)

Revised text:
MAX_DATA frame, which indicates the maximum of the sum of the absolute byte offsets of all streams.  A receiver maintains a cumulative sum of bytes received on all streams, which is used to  <ins> check for violations of the advertised connection or stream data limits.  A receiver might use a sum of bytes consumed on all streams to determine the maximum data limit to be advertised. </ins> Once a receiver advertises a limit for the connection or a stream, it MAY advertise a smaller limit, but this has no effect.