jiebi/TextFlow huggingface dataset:
Original text:
ack_delay_exponent, max_ack_delay, initial_source_connection_id, original_destination_connection_id, preferred_address, retry_source_connection_id, and stateless_reset_token.  The client <del> MUST use the server's new values in the handshake instead, and absent new values from the server, the default value. </del>  A client that attempts to send 0-RTT data MUST remember all other transport parameters used by the server.  The server can remember

Reviewer comments:
:
(Broken out of .) what does ‘absent’ mean in this clause, could you reword?

Revised text:
ack_delay_exponent, max_ack_delay, initial_source_connection_id, original_destination_connection_id, preferred_address, retry_source_connection_id, and stateless_reset_token.  The client  <ins> MUST use the server's new values in the handshake instead; if the server does not provide new values, the default value is used. </ins> A client that attempts to send 0-RTT data MUST remember all other transport parameters used by the server.  The server can remember
Original text:
When migrating, the new path might not support the endpoint's current sending rate.  Therefore, the endpoint resets its congestion <del> controller, as described in migration-cc. </del>  The new path might not have the same ECN capability.  Therefore, the endpoint verifies ECN capability as described in ecn.

Reviewer comments:
(Broken out of .) I assert the new path may not have the same RTT, because the path could traverse a different set of network devices or be subject to different policies that influence forwarding behaviour. These are not currently listed here, but are the basis for some later text in 9.3.1. Can we mention here?
Is the RTT not included in the reset of the congestion controller?
Section 9.4 reads: "The capacity available on the new path might not be the same as the old path. Packets sent on the old path MUST NOT contribute to congestion control or RTT estimation for the new path."
I sent a PR to add "and RTT estimate" to the sentence NAME quoted to make this completely clear.

Revised text:
When migrating, the new path might not support the endpoint's current sending rate.  Therefore, the endpoint resets its congestion  <ins> controller and RTT estimate, as described in migration-cc. </ins> The new path might not have the same ECN capability.  Therefore, the endpoint verifies ECN capability as described in ecn.
Original text:
8.4. <del> On receiving a PATH_CHALLENGE frame, an endpoint MUST respond immediately by echoing the data contained in the PATH_CHALLENGE frame in a PATH_RESPONSE frame. </del>  An endpoint MUST NOT send more than one PATH_RESPONSE frame in response to one PATH_CHALLENGE frame; see retransmission-of-

Reviewer comments:
This is the maximal version of a clarification of this text.
WFM, and resolves the original NiT.
(Broken out of .) Of course it may not be able to immediately send anything:-) , but I suspect this needs to not delay?
These frames aren't subject to flow control, so the only reason it would be unable to send something is congestion control. The frame that it echos back needs to be enqueued for sending; if it takes some time to actually hit the network, that's fine.
NAME
Seems resolved by the PR
For the benefit of others reviewing this: This seems to refer to .
This LG, but so did the old text.

Revised text:
8.4.  <ins> On receiving a PATH_CHALLENGE frame, an endpoint MUST respond by echoing the data contained in the PATH_CHALLENGE frame in a PATH_RESPONSE frame.  An endpoint MUST NOT delay transmission of a packet containing a PATH_RESPONSE frame unless constrained by congestion control. </ins> An endpoint MUST NOT send more than one PATH_RESPONSE frame in response to one PATH_CHALLENGE frame; see retransmission-of-
Original text:
server from repeated client probes, the PTO backoff is not reset at a client that is not yet certain that the server has finished validating the client's address.  That is, a client does not reset <del> the PTO backoff factor on receiving acknowledgements until it receives a HANDSHAKE_DONE frame or an acknowledgement for one of its Handshake or 1-RTT packets. </del>  This exponential reduction in the sender's rate is important because consecutive PTOs might be caused by loss of packets or unblock the server until it is certain that the server has finished its address validation (see Section 8 of QUIC-TRANSPORT).  That is, the client MUST set the probe timer if the client has not received an <del> acknowledgement for one of its Handshake or 1-RTT packets and has not received a HANDSHAKE_DONE frame, even if there are no packets in flight.  When the PTO fires, the client MUST send a Handshake packet if it has Handshake keys, otherwise it MUST send an Initial packet in a UDP datagram of at least 1200 bytes. </del>  6.2.3.

Reviewer comments:
This avoids redefinition of the conditions for handshake confirmation. It's fewer words, even with the extra references.
The draft should use "handshake confirmed" and point to the TLS draft instead of describing the conditions individually in various places.

Revised text:
server from repeated client probes, the PTO backoff is not reset at a client that is not yet certain that the server has finished validating the client's address.  That is, a client does not reset  <ins> the PTO backoff factor on receiving acknowledgements until the handshake is confirmed; see Section 4.1.2 of QUIC-TLS. </ins> This exponential reduction in the sender's rate is important because consecutive PTOs might be caused by loss of packets or unblock the server until it is certain that the server has finished its address validation (see Section 8 of QUIC-TRANSPORT).  That is, the client MUST set the probe timer if the client has not received an  <ins> acknowledgement for one of its Handshake packets and the handshake is not confirmed (see Section 4.1.2 of QUIC-TLS), even if there are no packets in flight.  When the PTO fires, the client MUST send a Handshake packet if it has Handshake keys, otherwise it MUST send an Initial packet in a UDP datagram of at least 1200 bytes. </ins> 6.2.3.
Original text:
17.2.5.3. <del> The next Initial packet from the client uses the connection ID and token values from the Retry packet; see negotiating-connection-ids. Aside from this, the Initial packet sent by the client is subject to the same restrictions as the first Initial packet.  A client MUST use the same cryptographic handshake message it included in this packet. A server MAY treat a packet that contains a different cryptographic handshake message as a connection error or discard it. </del>  A client MAY attempt 0-RTT after receiving a Retry packet by sending 0-RTT packets to the connection ID provided by the server.  A client

Reviewer comments:
See the issue for the sorry history of this mistake.
This issue has a long and storied history. We were originally of the view that only one packet needed to include a token (which you can see in the discussion of ). However, the resolution of that issue in was very clear: every Initial packet needs to include a token. That introduced a regression as it grouped the token with the connection ID, and we caught that in . However, the fix to that in reverted the token changes along with the connection ID changes. Since then, this error has gone unnoticed. Most people will have seen the stronger normative requirement : To my knowledge, every implementation includes the token in every Initial packet, changing only when a Retry is received. We should reconcile the text.
FWIW, that's what the interop runner tests for in the Retry test case.
NAME : Yes, that's what sent us off on this chase :-)

Revised text:
17.2.5.3.  <ins> Subsequent Initial packets from the client include the connection ID and token values from the Retry packet.  The client copies the Source Connection ID field from the Retry packet to the Destination Connection ID field and uses this value until an Initial packet with an updated value is received; see negotiating-connection-ids.  The value of the Token field is copied to all subsequent Initial packets; see validate-retry. Other than updating the Destination Connection ID and Token fields, the Initial packet sent by the client is subject to the same restrictions as the first Initial packet.  A client MUST use the same cryptographic handshake message it included in this packet.  A server MAY treat a packet that contains a different cryptographic handshake message as a connection error or discard it. </ins> A client MAY attempt 0-RTT after receiving a Retry packet by sending 0-RTT packets to the connection ID provided by the server.  A client
Original text:
frame.  A client sends MAX_PUSH_ID frames to control the number of pushes that a server can promise.  A server SHOULD use Push IDs sequentially, beginning from zero.  A client MUST treat receipt of a <del> push stream with a Push ID that is greater than the maximum Push ID as a connection error of type H3_ID_ERROR. </del>  The Push ID is used in one or more PUSH_PROMISE frames (frame-push- promise) that carry the header section of the request message.  These

Reviewer comments:
Probably editorial since this is what was previously intended, but still touching a MUST.
states: The case when the client has not sent a MAXPUSHID frame is not covered. (In this case, the client should treat the receipt of any frame with a Push ID as an error.)
There is some other text that kinda marks the error case: One interpretation is that since any value of ID is greater than , then the error condition holds. But I agree with Dmitri that we could probably make this clearer with some editorializing.
That's a big stretch. Does it hold in languages that have a , such as JavaScript? E.g., can one write ?
Since it starts as unset, and MAXPUSHID can only increase the value then in this world, 0 must be greater than unset
What is "unset?" &lt;DmitriMode>If 0 is a valid value, then "unset" means , which is not smaller than 0. That is, it is not true that , which is what the text says.&lt;/DmitriMode>
Sure, but then it makes it very hard to send a MAXPUSHID that doesn't decrease the value. I think we agree that it would help the doc to fix your original nitpick.
Unset is negative one? The frame sets a boolean? This seems easy enough to implement in practice, but you're correct that the doc is effectively using a nullable type. I see a couple possible doc fixes. The most minimal change is to simply state that it is also an error to receive anything that uses a Push ID if no MAXPUSHID frame has been sent. That's compatible and consistent with the intent of the current design. Alternatively, we could define MAXPUSHID to tell the recipient how many Push IDs they can use; 0 is the initial value, and sending 0 leaves push disabled. That's consistent with QUIC's MAXSTREAMS et al. but would be a breaking change.
I vote for the simplest approach:
+1 let's keep it simple
Editorial?
Yes, this is an editorial issue.

Revised text:
frame.  A client sends MAX_PUSH_ID frames to control the number of pushes that a server can promise.  A server SHOULD use Push IDs sequentially, beginning from zero.  A client MUST treat receipt of a  <ins> push stream as a connection error of type H3_ID_ERROR when no MAX_PUSH_ID frame has been sent or when the stream references a Push ID that is greater than the maximum Push ID. </ins> The Push ID is used in one or more PUSH_PROMISE frames (frame-push- promise) that carry the header section of the request message.  These
Original text:
To avoid excessively small idle timeout periods, endpoints MUST increase the idle timeout period to be at least three times the <del> current Probe Timeout (PTO).  This allows for multiple PTOs to expire prior to idle timeout, ensuring the idle timeout does not expire as a result of a single packet loss. </del>  10.1.1.

Reviewer comments:
I think this was the intent of the sentence, but I kept not being able to parse it so.

Revised text:
To avoid excessively small idle timeout periods, endpoints MUST increase the idle timeout period to be at least three times the  <ins> current Probe Timeout (PTO).  This allows for multiple PTOs to expire, and therefore multiple probes to be sent in the event of loss, prior to idle timeout. </ins> 10.1.1.
Original text:
these countermeasures could be insufficient if UDP-based services do not properly authorize requests.  21.4.1. QUIC offers some opportunities for an attacker to influence or

Reviewer comments:
I also think it might be worthwhile to move much of this section to security considerations, leaving only the requirements here. NAME WDYT?
This is already in the security considerations section, so we're good. Though it's hard to see, because the section is already so large.
I find Martin's argument that QUIC servers are able to control their topology well enough to prevent request forgery attacks somewhat persuasive. However: I think the document should be clearer that if you can't do this you can't deploy QUIC as a server. We should add text indicating that a candidate extension to allow migration by the client would need to deal with this (likely by adding one of the countermeasures we decided not to ass). This is a very long specification and otherwise the institutional knowledge about this issue is likely to be lost.
If people agree, I can provide PRs for these.
These sound like good additions that I would welcome. (I would write the PR, but I don't trust myself, I'd appreciate you providing text.)
Sounds like a good path forward.
Do you mean migration by the server?
I'm not clear on the grammar, but I mean "the server address changing"
FWIW, when we've talked about a server migration extension before, it was usually in the form of a frame that mimics the preferred_address TP, prompting the client to probe the new address and actually make the change. That approach seems like it limits the attacks to those already possible with SPA, though it broadens the window / number of attempts.
Could people take a look at the PR? Would like to move this along.
Thanks for writing this up. My only comment is that this is two points and therefore two paragraphs.

Revised text:
these countermeasures could be insufficient if UDP-based services do not properly authorize requests. <ins> Because the migration attack described in request-forgery-with- spoofed-migration is quite powerful and does not have adequate countermeasures, QUIC server implementations should assume that attackers can cause them to generate arbitrary UDP payloads to arbitrary destinations.  QUIC servers SHOULD NOT be deployed in networks that also have inadequately secured UDP endpoints. Although it is not generally possible to ensure that clients are not co-located with vulnerable endpoints, this version of QUIC does not allow servers to migrate, thus preventing spoofed migration attacks on clients.  Any future extension which allows server migration MUST also define countermeasures for forgery attacks. </ins> 21.4.1. QUIC offers some opportunities for an attacker to influence or
Original text:
use a pre-shared key and validated the client's pre-shared key binder; see Section 4.2.11 of TLS13. <del> The client has not demonstrated liveness, unless a RETRY packet was used. </del>  Any received 0-RTT data that the server responds to might be due to a replay attack.

Reviewer comments:
Three minor changes here; separate if needed: The section title refers to frames, but the content discusses packets The text refers to a RETRY packet; packet types are not shouting-case Retry is not the only way to verify liveness prior to handshake completion (e.g. Connection ID on packets with a multi-round-trip handshake); reference to address validation for more context

Revised text:
use a pre-shared key and validated the client's pre-shared key binder; see Section 4.2.11 of TLS13.  <ins> The client has not demonstrated liveness, unless the server has validated the client's address with a Retry packet or other means; see Section 8.1 of QUIC-TRANSPORT. </ins> Any received 0-RTT data that the server responds to might be due to a replay attack.
Original text:
round-trip time multiplier, is 9/8.  The RECOMMENDED value of the timer granularity (kGranularity) is 1ms.  Implementations MAY experiment with absolute thresholds, thresholds from previous connections, adaptive thresholds, or including RTT variation.  Smaller thresholds reduce reordering resilience and

Reviewer comments:
This draft already has an informative reference to RACK, so it seems sensible to note the small difference in time threshold.

Revised text:
round-trip time multiplier, is 9/8.  The RECOMMENDED value of the timer granularity (kGranularity) is 1ms. <ins> TCP's RACK (RACK) specifies a slightly larger threshold, equivalent to 5/4, for a similar purpose.  Experience with QUIC shows that 9/8 works well. </ins> Implementations MAY experiment with absolute thresholds, thresholds from previous connections, adaptive thresholds, or including RTT variation.  Smaller thresholds reduce reordering resilience and
Original text:
discretionary as, depending on circumstances, they could interfere with or prevent legitimate uses. <del> Services offered over loopback interfaces (that is, the IPv6 address ::1 or the IPv4 address 127.0.0.1) often lack proper authentication. Endpoints MAY prevent connection attempts or migration to a loopback address.  Endpoints SHOULD NOT allow connections or migration to a loopback address if the same service was previously available at a different interface or if the address was provided by a service at a non-loopback address.  Endpoints that depend on these capabilities could offer an option to disable these protections. </del>  Similarly, endpoints could regard a change in address to link-local address RFC4291 or an address in a private use range RFC1918 from a

Reviewer comments:
Text says >Services offered over loopback interfaces (that is, the IPv6 address ::1 or the IPv4 address 127.0.0.1) often lack proper authentication. On v4, loopback is technically the entire 127.0.0.0/8 network, not just that one address. But I wonder if we need the parenthetical anyway?

Revised text:
discretionary as, depending on circumstances, they could interfere with or prevent legitimate uses.  <ins> Services offered over loopback interfaces often lack proper authentication.  Endpoints MAY prevent connection attempts or migration to a loopback address.  Endpoints SHOULD NOT allow connections or migration to a loopback address if the same service was previously available at a different interface or if the address was provided by a service at a non-loopback address.  Endpoints that depend on these capabilities could offer an option to disable these protections. </ins> Similarly, endpoints could regard a change in address to link-local address RFC4291 or an address in a private use range RFC1918 from a
Original text:
bytes. UDP datagrams MUST NOT be fragmented at the IP layer.  In IPv4 <del> (IPv4), the DF bit MUST be set to prevent fragmentation on the path. </del>  14.1.

Reviewer comments:
For example, OSX doesn't have an API to set this bit (allegedly this will change with Big Sur). Furthermore, not all implementations might have access to an API that allows them to set bits in the IP header. If I remember correctly, this is one of the reasons we made ECN optional.
I think you wanted to quote this part ({{!IPv4=RFC0791}}), the DF bit MUST be set to prevent fragmentation on the path. Would a proposal be to make the MUST a SHOULD and say "unless this is not supported by the underlying OS"?
Yes, that was a weird copy-paste error. If we say "unless this is not supported by the underlying OS or the programming language" we can probably even keep the MUST.
This is an editorial issue, since the intent of the MUST cannot be to require something that isn't possible.
This seems fine. What do you think of the short version?

Revised text:
bytes. UDP datagrams MUST NOT be fragmented at the IP layer.  In IPv4  <ins> (IPv4), the DF bit MUST be set if possible, to prevent fragmentation on the path. </ins> 14.1.
Original text:
authenticated negotiation of an application protocol (TLS uses ALPN ALPN for this purpose) <del> An endpoint verifies support for Explicit Congestion Notification (ECN) by observing whether the ACK frames acknowledging the first packets it sends carry ECN counts, as described in ecn-validation. </del>  The CRYPTO frame can be sent in different packet number spaces (packet-numbers).  The offsets used by CRYPTO frames to ensure

Reviewer comments:
Yeah, this is better.
The sentence observing whether the ACK frames acknowledging the first packets it sends carry ECN counts, as described in {{ecn-validation}}. seems to not belong into that section.
Assuming one enables ECN on Initial and Handshake packets in order to perform ECN validation, then I think it's the right place?
NAME are you OK with NAME explanation, i.e., can we close with no action?
Not really happy with it, tbh. The sentence feels completely out of place as it stands now. I think we should either move it to the ECN section (I think that would make the most sense), or at least add an introductory sentence, along these lines:
I like the introductory sentence.
WFMThis is good, thanks!

Revised text:
authenticated negotiation of an application protocol (TLS uses ALPN ALPN for this purpose)  <ins> Endpoints can use packets sent during the handshake to test for Explicit Congestion Notification (ECN) support; see ecn.  An endpoint verifies support for ECN by observing whether the ACK frames acknowledging the first packets it sends carry ECN counts, as described in ecn-validation. </ins> The CRYPTO frame can be sent in different packet number spaces (packet-numbers).  The offsets used by CRYPTO frames to ensure
Original text:
7.1. <del> If a path has been verified to support ECN (RFC3168, RFC8311), QUIC </del>  treats a Congestion Experienced (CE) codepoint in the IP header as a signal of congestion.  This document specifies an endpoint's response when its peer receives packets with the ECN-CE codepoint. shown with a '*'.  Once completed, endpoints are able to exchange application data. <del> An endpoint verifies support for Explicit Congestion Notification </del>  (ECN) by observing whether the ACK frames acknowledging the first packets it sends carry ECN counts, as described in ecn-validation. controller and RTT estimate, as described in migration-cc. The new path might not have the same ECN capability.  Therefore, the <del> endpoint verifies ECN capability as described in ecn. </del>  9.3.

Reviewer comments:
URL verified. Consistency in terms helps.
mentions /verification/ of ECN but defines /validation/ of ECN.: In section 9.2: the term /verify/ is used 3 times, but not explained: /verifies ECN capability/ and /verifies ECN support/ should these both be /validates ECN support/ ? … ALSO is there a difference between ECN support and ECN capability? - I didn’t expect a subtle difference, can we use one set of words instead? (and sorry if I compounded any confusion in the terms...)

Revised text:
7.1.  <ins> If a path has been validated to support ECN (RFC3168, RFC8311), QUIC </ins> treats a Congestion Experienced (CE) codepoint in the IP header as a signal of congestion.  This document specifies an endpoint's response when its peer receives packets with the ECN-CE codepoint. shown with a '*'.  Once completed, endpoints are able to exchange application data.  <ins> An endpoint validates support for Explicit Congestion Notification </ins> (ECN) by observing whether the ACK frames acknowledging the first packets it sends carry ECN counts, as described in ecn-validation. controller and RTT estimate, as described in migration-cc. The new path might not have the same ECN capability.  Therefore, the  <ins> endpoint validates ECN capability as described in ecn. </ins> 9.3.