jiebi/TextFlow huggingface dataset:
Original text:
The payload of a UDP datagram carrying the first Initial packet MUST be expanded to at least 1200 bytes, by adding PADDING frames to the <del> Initial packet and/or by combining the Initial packet with a 0-RTT packet (see packet-coalesce).  Sending a UDP datagram of this size ensures that the network path supports a reasonable Maximum Transmission Unit (MTU), and helps reduce the amplitude of amplification attacks caused by server responses toward an unverified client address; see address-validation. </del>  The datagram containing the first Initial packet from a client MAY exceed 1200 bytes if the client believes that the Path Maximum

Reviewer comments:
It doesn't matter what an Initial is coalesced with. It could be a 0-RTT packet, it could be an (invalid) Handshake packet, or the bytes after the Initial packet could be completely random. The only thing that matters is that the resulting UDP datagram has at least 1200 bytes.
CI failure isn't my fault. The faulty commit seems to be bbe2b80d490c39c1d5900a5f00b4bbe11a29c4df.

Revised text:
The payload of a UDP datagram carrying the first Initial packet MUST be expanded to at least 1200 bytes, by adding PADDING frames to the  <ins> Initial packet and/or by coalescing the Initial packet (see packet- coalesce).  Sending a UDP datagram of this size ensures that the network path supports a reasonable Maximum Transmission Unit (MTU), and helps reduce the amplitude of amplification attacks caused by server responses toward an unverified client address; see address- validation. </ins> The datagram containing the first Initial packet from a client MAY exceed 1200 bytes if the client believes that the Path Maximum
Original text:
cease retransmission of the closing packet. Disposing of connection state prior to the end of the closing or <del> draining period could cause delayed or reordered packets to be handled poorly.  Endpoints that have some alternative means to ensure that late-arriving packets on the connection do not create QUIC state, such as those that are able to close the UDP socket, MAY use an abbreviated draining period which can allow for faster resource recovery.  Servers that retain an open socket for accepting new connections SHOULD NOT exit the closing or draining period early. </del>  Once the closing or draining period has ended, an endpoint SHOULD discard all connection state.  This results in new packets on the

Reviewer comments:
FWIW, the state that was implied was the creation of a new connection. That's not realistic in QUICv1 however, so this is good.
I'm not following why in general this would create state. If the handshake has occurred > MSL ago, and you just refuse to create state on short packets with unknown CIDs s, why isn't that enough?
This was written when there was some uncertainty about what packets might look like. I think that we can truncate this sentence. Basically, you can drop state earlier, but it will mean that you won't be able to attribute any laggardly packets properly.

Revised text:
cease retransmission of the closing packet. Disposing of connection state prior to the end of the closing or  <ins> draining period could cause delayed or reordered packets to generate an unnecessary stateless reset.  Endpoints that have some alternative means to ensure that late-arriving packets on the connection do not induce a response, such as those that are able to close the UDP socket, MAY use an abbreviated draining period which can allow for faster resource recovery.  Servers that retain an open socket for accepting new connections SHOULD NOT exit the closing or draining period early. </ins> Once the closing or draining period has ended, an endpoint SHOULD discard all connection state.  This results in new packets on the
Original text:
4.3.  Server push is an interaction mode introduced in HTTP/2 HTTP2 which permits a server to push a request-response exchange to a client in anticipation of the client making the indicated request.  This trades

Reviewer comments:
Is it worth adding a reference to RFC 8441? That's an alternative that covers what people looking for this functionality were probably trying to do.
That's a good point, let me craft something up and I'll update the PR soon.
Ping NAME unless you'd like me to take it over.
I'll get an update out tomorrow
I'm actually not convinced that referencing 8441 will help clarify things here because the extension is H2 specific. No H3-equivalent exists (or at least, no H3 setting to enable the equivalent CONNECT behaviour exists).
I agree. I think referencing 8441 might just add to the confusion - even if something like 8441 certainly can be introduced.
Some others have shown interest for defining/framing this capability in HTTP/3. I think that activity should consider ore broadly what text makes sense in the core document.
Fair enough. Let's merge the rebased version, then, and leave the right way to do this for an H3 extension.
HTTP/3 makes no explicit comment about this. HTTP/2 prohibits it. So I think that we might want to add equivalent text. URL informational status code ([RFC7231], Section 6.2.2). multiplexed protocol.

Revised text:
4.3. <ins> HTTP/3 does not support the HTTP Upgrade mechanism (RFC7230, Section 6.7) or 101 (Switching Protocols) informational status code (RFC7231, Section 6.2.2). 4.4. </ins> Server push is an interaction mode introduced in HTTP/2 HTTP2 which permits a server to push a request-response exchange to a client in anticipation of the client making the indicated request.  This trades
Original text:
6.2. <del> A Probe Timeout (PTO) triggers sending one or two probe packets when ack-eliciting packets are not acknowledged within the expected period of time or the handshake has not been completed.  A PTO enables a connection to recover from loss of tail packets or acks.  The PTO algorithm used in QUIC implements the reliability functions of Tail Loss Probe TLP RACK, RTO RFC5681 and F-RTO algorithms for TCP RFC5682, and the timeout computation is based on TCP's retransmission timeout period RFC6298. </del>  6.2.1. When a PTO timer expires, a sender MUST send at least one ack- eliciting packet as a probe, unless there is no data available to <del> send.  An endpoint MAY send up to two ack-eliciting packets, to avoid an expensive consecutive PTO expiration due to a single packet loss. </del>  It is possible that the sender has no new or previously-sent data to send.  As an example, consider the following sequence of events: new

Reviewer comments:
Now that the PTO retransmits Initial and Handshake data, it's possible and likely desirable to bundle multiple QUIC packets in a single datagram. This change makes it clear that is allowed.
nits, but lgtm

Revised text:
6.2.  <ins> A Probe Timeout (PTO) triggers sending one or two probe datagrams when ack-eliciting packets are not acknowledged within the expected period of time or the handshake has not been completed.  A PTO enables a connection to recover from loss of tail packets or acknowledgements.  The PTO algorithm used in QUIC implements the reliability functions of Tail Loss Probe TLP RACK, RTO RFC5681 and F-RTO algorithms for TCP RFC5682, and the timeout computation is based on TCP's retransmission timeout period RFC6298. </ins> 6.2.1. When a PTO timer expires, a sender MUST send at least one ack- eliciting packet as a probe, unless there is no data available to  <ins> send.  An endpoint MAY send up to two full-sized datagrams containing ack-eliciting packets, to avoid an expensive consecutive PTO expiration due to a single lost datagram. </ins> It is possible that the sender has no new or previously-sent data to send.  As an example, consider the following sequence of events: new
Original text:
1-RTT keys have forward secrecy <del> authenticated values for the transport parameters of the peer (see transport-parameters) </del>  authenticated negotiation of an application protocol (TLS uses ALPN RFC7301 for this purpose)

Reviewer comments:
The TPs might carry a stateless reset token, which must be encrypted in transit. Section 7 in the transport document [1] lists some requirements for the handshake, including authentication of the TPs, yet does not include any mention of encrypting them from server to client. Should it? cc NAME NAME [1] URL
This makes sense to me. The TLS document ensures that the server's transport parameters are encrypted so an editorial PR changing the transport doc to require that should be sufficient.
Good catch. Marking as design so that we can consensus call this, but it's arguably editorial.

Revised text:
1-RTT keys have forward secrecy  <ins> authenticated values for transport parameters of both endpoints, and confidentiality protection for server transport parameters (see transport-parameters) </ins> authenticated negotiation of an application protocol (TLS uses ALPN RFC7301 for this purpose)
Original text:
by the endpoint upon receipt. Connection IDs MUST NOT contain any information that can be used by <del> an external observer to correlate them with other connection IDs for the same connection.  As a trivial example, this means the same connection ID MUST NOT be issued more than once on the same connection. </del>  Packets with long headers include Source Connection ID and Destination Connection ID fields.  These fields are used to set the

Reviewer comments:
S 5.1. says At minimum this needs to be restricted to endpoints and other elements associated with them (like load balancers) because they need to be able to correlate connection IDs. But this is also a very strong condition, and in some cases will basically mandate encryption.
It should contain "by an external observer". I believe there is other text mentioning coordination with load balancers when constructing CID's. It is a strong condition - without it all other work on preventing linkage is more or less useless.
It feels strange to me that this is an RFC8174 MUST NOT, as it's unclear how to enforce it. That said, I agree that this text should be constrained to external observers - and clearly define who that is.
Maybe change to “Connection IDs MUST NOT expose”?
Tokyo conclusion: describe what the attack is and explain that anti-correlation text exists as an answer to this. The normative language is perhaps too strong, given that it might be possible to create smaller anonymity sets and still have a reasonable answer to the attack.
Discussed in London, NAME to resume work
NAME how is this progressing?
I believe this is an editorial issue, not design. We all know what we mean: it can encode information by use for itself and trusted intermediaries, but definitely is not correlatable. I agree that MUST is a little tricky unless we are mandating either true encryption or true randomness, which is a discussion I was hoping to defer until QUIC-LB is adopted.
Looks fine. This paragraph is wrapped to a shorter line-length than the standard for the document.

Revised text:
by the endpoint upon receipt. Connection IDs MUST NOT contain any information that can be used by  <ins> an external observer (that is, one that does not cooperate with the issuer) to correlate them with other connection IDs for the same connection.  As a trivial example, this means the same connection ID MUST NOT be issued more than once on the same connection. </ins> Packets with long headers include Source Connection ID and Destination Connection ID fields.  These fields are used to set the
Original text:
greater than its own Insert Count, the stream cannot be processed immediately, and is considered "blocked" (see {blocked-decoding}). <del> The SETTINGS_QPACK_BLOCKED_STREAMS setting (see configuration) specifies an upper bound on the number of streams which can be blocked.  An encoder MUST limit the number of streams which could become blocked to the value of SETTINGS_QPACK_BLOCKED_STREAMS at all times.  Note that the decoder might not become blocked on every stream which risks becoming blocked. </del>  An encoder can decide whether to risk having a stream become blocked. If permitted by the value of SETTINGS_QPACK_BLOCKED_STREAMS, it MAY treat this as a connection error of type HTTP_QPACK_DECOMPRESSION_FAILED. <del> If the decoder encounters more blocked streams than it promised to support, it MUST treat this as a connection error of type HTTP_QPACK_DECOMPRESSION_FAILED. </del> 2.2.2. The decoder signals the following events by emitting decoder

Reviewer comments:
Emphasize that SETTINGSQPACKBLOCKED_STREAMS is set by the decoder. Move normative sentence on decoder encountering excessive number of blocked streams to this paragraph. Split note to separate paragraph.
:+1: This reads much better to me.

Revised text:
greater than its own Insert Count, the stream cannot be processed immediately, and is considered "blocked" (see {blocked-decoding}).  <ins> The decoder specifies an upper bound on the number of streams which can be blocked using the SETTINGS_QPACK_BLOCKED_STREAMS setting (see configuration).  An encoder MUST limit the number of streams which could become blocked to the value of SETTINGS_QPACK_BLOCKED_STREAMS at all times.  If an decoder encounters more blocked streams than it promised to support, it MUST treat this as a connection error of type HTTP_QPACK_DECOMPRESSION_FAILED. Note that the decoder might not become blocked on every stream which risks becoming blocked. </ins> An encoder can decide whether to risk having a stream become blocked. If permitted by the value of SETTINGS_QPACK_BLOCKED_STREAMS, it MAY treat this as a connection error of type HTTP_QPACK_DECOMPRESSION_FAILED.  2.2.2. The decoder signals the following events by emitting decoder
Original text:
The Header Acknowledgement and Stream Cancellation instructions permit the encoder to remove references to entries in the dynamic <del> table.  When entries have zero references they are no longer considered blocking (see blocked-insertion). </del>  2.2.2.3.

Reviewer comments:
The definition of a blocking entry has two parts: insertion not acknowledged, or not all references acknowledged. Update text in two places to include the part about acknowledging the insertion, lest a reader forget about it.

Revised text:
The Header Acknowledgement and Stream Cancellation instructions permit the encoder to remove references to entries in the dynamic  <ins> table.  When an entry with absolute index lower than the Known Received Count has zero references, then it is no longer considered blocking (see blocked-insertion). </ins> 2.2.2.3.
Original text:
2.2.2.1. <del> When the decoder finishes decoding a header block containing dynamic </del>  table references, it MUST emit a Header Acknowledgement instruction (header-acknowledgement).  A stream may carry multiple header blocks in the case of intermediate responses, trailers, and pushed requests.

Reviewer comments:
Add MUST to sentence about requirement on decoder to emit a Header Acknowledgement instruction every time it decodes a header block with non-zero Required Insert Count.
That's a good point, I haven't thought about it. Would changing "When the decoder finishes decoding..." to "After the decoder finishes decoding..." be sufficient to allow for delayed ACKs?
Works for me.
Done. Thanks for raising this issue.
You can't coalesce Header Acks like you can Insert Count Increment or transport Acks. The only overhead savings comes from when these are sent to the peer - eg: transport overhead. The text only says the Ack, and doesn't really describe how quickly it has to be conveyed. But I don't really have a problem with when vs. after either.
This doesn't allow for a delay in sending an ack. That delay might be useful in reducing overheads. That might be a new issue though.

Revised text:
2.2.2.1.  <ins> After the decoder finishes decoding a header block containing dynamic </ins> table references, it MUST emit a Header Acknowledgement instruction (header-acknowledgement).  A stream may carry multiple header blocks in the case of intermediate responses, trailers, and pushed requests.
Original text:
A unique index for each entry in the dynamic table. <del> A reference point for relative indices.  Dynamic references are made relative to a Base in header blocks. </del>  The total number of entries inserted in the dynamic table. For example, with a Required Insert Count of 9, a decoder receives a S bit of 1 and a Delta Base of 2.  This sets the Base to 6 and enables post-base indexing for three entries.  In this example, a <del> regular index of 1 refers to the 5th entry that was added to the </del>  table; a post-base index of 1 refers to the 8th entry. 4.5.2.

Reviewer comments:
Since post-base index has a section separate from relative index, I do not consider post-base index a type of relative index, but a distinct category. Update text accordingly. If the consensus is that this is not the case, relative index and post-base index sections should be reworded, and a new term should be introduced for non-post-base relative index.

Revised text:
A unique index for each entry in the dynamic table.  <ins> A reference point for relative and post-base indices.  References to dynamic table entries in header blocks are relative to a Base. </ins> The total number of entries inserted in the dynamic table. For example, with a Required Insert Count of 9, a decoder receives a S bit of 1 and a Delta Base of 2.  This sets the Base to 6 and enables post-base indexing for three entries.  In this example, a  <ins> relative index of 1 refers to the 5th entry that was added to the </ins> table; a post-base index of 1 refers to the 8th entry. 4.5.2.
Original text:
Unlike TLS over TCP, QUIC applications which want to send data do not send it through TLS "application_data" records.  Rather, they send it <del> as QUIC STREAM frames which are then carried in QUIC packets. </del>  4.

Reviewer comments:
Mention that application data could be conveyed in other frame types than STREAM frames. (E.g. the proposed DATAGRAM draft sends application data in DATAGRAM frames.)
This was correct at the time, because only STREAM carried application semantics, but that's too constraining, even now. Thanks.

Revised text:
Unlike TLS over TCP, QUIC applications which want to send data do not send it through TLS "application_data" records.  Rather, they send it  <ins> as QUIC STREAM frames or other frame types which are then carried in QUIC packets. </ins> 4.
Original text:
8. QUIC uses the TLS handshake for more than just negotiation of <del> cryptographic parameters.  The TLS handshake validates protocol version selection, provides preliminary values for QUIC transport parameters, and allows a server to perform return routability checks on clients. </del>  8.1.

Reviewer comments:
I'm pretty sure this was obsoleted when version negotiation was removed (along with initial/negotiated/supported versions from transport parameters). If you think the TLS handshake is still validating protocol version selection, feel free to reject this PR.

Revised text:
8. QUIC uses the TLS handshake for more than just negotiation of  <ins> cryptographic parameters.  The TLS handshake provides preliminary values for QUIC transport parameters and allows a server to perform return routability checks on clients. </ins> 8.1.
Original text:
19.6. The CRYPTO frame (type=0x06) is used to transmit cryptographic <del> handshake messages.  It can be sent in all packet types.  The CRYPTO frame offers the cryptographic protocol an in-order stream of bytes. CRYPTO frames are functionally identical to STREAM frames, except that they do not bear a stream identifier; they are not flow </del>  controlled; and they do not carry markers for optional offset, optional length, and the end of the stream.

Reviewer comments:
Thanks! Beat me to it.
In quic-transport-22 section 19.6 it says CRYPTO frames can be sent in all packet types. However in quic-tls-22 section 4 it says the CRYPTO frames can't be sent in 0-RTT packets. Also in quic-tls-22 section 8.3, similar statement. Maybe the statement in quic-transport-22 needs to be corrected?

Revised text:
19.6. The CRYPTO frame (type=0x06) is used to transmit cryptographic  <ins> handshake messages.  It can be sent in all packet types except 0-RTT. The CRYPTO frame offers the cryptographic protocol an in-order stream of bytes.  CRYPTO frames are functionally identical to STREAM frames, except that they do not bear a stream identifier; they are not flow </ins> controlled; and they do not carry markers for optional offset, optional length, and the end of the stream.
Original text:
The three ECN Counts are: A variable-length integer representing the total number of packets <del> received with the ECT(0) codepoint. </del>  A variable-length integer representing the total number of packets <del> received with the ECT(1) codepoint. </del>  A variable-length integer representing the total number of packets <del> received with the CE codepoint. </del>  ECN counts are maintained separately for each packet number space.

Reviewer comments:
Specify that ECN counts in the ACK frame to be in the same pn_space of the ACK frame. Change pseudocode in recovery-draft to reflect that.
This only changes pseudocode and no normative text, so I'm inclined to mark it editorial and merge it.
Are ECN counts in ACK frames per pnspace or unified across pnspaces? I've observed different behaviors of public servers regarding that. [13.3.1. ECN Counts] seems to suggest they are per pnspace: However, [19.3.2. ECN Counts] says: Pseudocode in the recovery draft (Appendix B. Congestion Control Pseudocode) also has a global ecnce_counter.
Thanks for the issue, NAME PR looks good.
Thanks! NAME want to take a look?

Revised text:
The three ECN Counts are: A variable-length integer representing the total number of packets  <ins> received with the ECT(0) codepoint in the packet number space of the ACK frame. </ins> A variable-length integer representing the total number of packets  <ins> received with the ECT(1) codepoint in the packet number space of the ACK frame. </ins> A variable-length integer representing the total number of packets  <ins> received with the CE codepoint in the packet number space of the ACK frame. </ins> ECN counts are maintained separately for each packet number space.
Original text:
Normally, clients will open streams sequentially, as explained in stream-id.  However, when several streams are initiated at short <del> intervals, transmission error may cause STREAM DATA frames opening streams to be received out of sequence.  A receiver is obligated to open intervening streams if a higher-numbered stream ID is received. Thus, on a new connection, opening stream 2000001 opens 1 million streams, as required by the specification. </del>  The number of active streams is limited by the initial_max_streams_bidi and initial_max_streams_uni transport

Reviewer comments:
The Stream Commitment Attack part was added in draft-ietf-quic-transport-03, when unidirectional streams were not used. In draft-ietf-quic-transport-08, streams were split into unidirectional and bidirectional, but this example of stream commitment attack was missed.
Thanks, NAME I've done some editorializing, and merging.

Revised text:
Normally, clients will open streams sequentially, as explained in stream-id.  However, when several streams are initiated at short  <ins> intervals, loss or reordering may cause STREAM frames that open streams to be received out of sequence.  On receiving a higher- numbered stream ID, a receiver is required to open all intervening streams of the same type (see stream-recv-states).  Thus, on a new connection, opening stream 4000000 opens 1 million and 1 client- initiated bidirectional streams. </ins> The number of active streams is limited by the initial_max_streams_bidi and initial_max_streams_uni transport