Pre-PTO CRYPTO retransmission limits are not fully established
Problem Description
The test cases exercise the same RFC 9002 Section 6.2.4 requirement for a finite per-connection limit on sending unacknowledged CRYPTO data before PTO expiry. Static review left unresolved preconditions, and no implementation-specific executable reproducer was available in the current run.
Standard Requirement
an endpoint
MAY, for a limited number of times per connection, send a packet
containing unacknowledged CRYPTO data earlier than the PTO expiry
Interpretation: when an endpoint uses the pre-PTO transmission optimization for unacknowledged CRYPTO data, it must impose a finite per-connection limit. It must not apply that optimization an unlimited number of times on one connection.
Relevant Source Code
The requirement was mapped to s2n-quic PTO and congestion-control source categories. The cited source shows the relevant probe transmission mechanism, but static review alone did not close every precondition, cross-state behavior, or runtime observable needed for a conclusion.
quic/s2n-quic-core/src/recovery/pto.rs:17-31
impl Pto {
/// Called when a timeout has occurred. Returns `Ready` if the PTO timer had expired.
#[inline]
pub fn on_timeout(&mut self, packets_in_flight: bool, timestamp: Timestamp) -> Poll<()> {
ensure!(
self.timer.poll_expiration(timestamp).is_ready(),
Poll::Pending
);
//= https://www.rfc-editor.org/rfc/rfc9002#section-6.2.4
//# When a PTO timer expires, a sender MUST send at least one ack-
//# eliciting packet in the packet number space as a probe.
//= https://www.rfc-editor.org/rfc/rfc9002#section-6.2.2.1
//# Since the server could be blocked until more datagrams are received
PTO timeout handling is the trigger point for sending at least one ack-eliciting probe packet.
quic/s2n-quic-core/src/recovery/pto.rs:95-152
impl transmission::Provider for Pto {
#[inline]
fn on_transmit<W: transmission::Writer>(&mut self, context: &mut W) {
ensure!(context.transmission_mode().is_loss_recovery_probing());
ensure!(self.has_transmission_interest());
//= https://www.rfc-editor.org/rfc/rfc9002#section-6.2.4
//# All probe packets sent on a PTO MUST be ack-eliciting.
if !context.ack_elicitation().is_ack_eliciting() {
let frame = frame::Ping;
//= https://www.rfc-editor.org/rfc/rfc9002#section-7.5
//# Probe packets MUST NOT be blocked by the congestion controller.
ensure!(context.write_frame_forced(&frame).is_some());
}
self.on_transmit_once();
}
}
impl transmission::interest::Provider for Pto {
#[inline]
fn transmission_interest<Q: transmission::interest::Query>(
&self,
query: &mut Q,
) -> transmission::interest::Result {
if self.transmissions() > 0 {
query.on_forced()?;
}
Ok(())
}
}
PTO probe transmission forces an ack-eliciting PING when no other ack-eliciting frame is present and uses forced transmission interest.
quic/s2n-quic-transport/src/connection/transmission.rs:119-141
//= https://www.rfc-editor.org/rfc/rfc9002#section-7
//# An endpoint MUST NOT send a packet if it would cause bytes_in_flight
//# (see Appendix B.2) to be larger than the congestion window, unless
//# the packet is sent on a PTO timer expiration (see Section 6.2) or
//# when entering recovery (see Section 7.3.2).
let transmission_constraint =
if space_manager.requires_probe() && self.context.transmission_mode.is_normal() {
//= https://www.rfc-editor.org/rfc/rfc9002#section-6.2.4
//# When a PTO timer expires, a sender MUST send at least one ack-
//# eliciting packet in the packet number space as a probe.
//= https://www.rfc-editor.org/rfc/rfc9002#section-6.2.4
//# An endpoint SHOULD include new data in packets that are sent on PTO
//# expiration. Previously sent data MAY be sent if no new data can be
//# sent.
//= https://www.rfc-editor.org/rfc/rfc9002#section-7.5
//# Probe packets MUST NOT be blocked by the congestion controller.
self.context.transmission_mode = transmission::Mode::LossRecoveryProbing;
transmission::Constraint::None
} else {
self.context.path().transmission_constraint()
};
Normal transmission is constrained by congestion window, while PTO probing switches to LossRecoveryProbing with no congestion constraint.
quic/s2n-quic-transport/src/recovery/manager.rs:219-276
let congestion_controlled_bytes = if outcome.is_congestion_controlled {
outcome.bytes_sent
} else {
0
};
let path_id = context.path_id();
let path = context.path_mut();
let cc_packet_info = path.congestion_controller.on_packet_sent(
time_sent,
congestion_controlled_bytes,
app_limited,
&path.rtt_estimator,
&mut congestion_controller::PathPublisher::new(publisher, path_id),
);
self.sent_packets.insert(
packet_number,
SentPacketInfo::new(
outcome.is_congestion_controlled,
congestion_controlled_bytes,
time_sent,
outcome.ack_elicitation,
path_id,
ecn,
transmission_mode,
cc_packet_info,
),
);
if outcome.ack_elicitation.is_ack_eliciting() {
self.time_of_last_ack_eliciting_packet = Some(time_sent);
self.pto_update_pending = true;
}
Sent packet accounting excludes ACK-only packets from congestion control, but records congestion-controlled packets, including probes, in sent packet state.
Runtime Evidence
Positive controls were run for representative RTT, PTO, loss, ACK, and persistent-congestion behavior. They passed with exit code 0, showing that the basic recovery test environment was operational.
The implementation-specific focused reproducers were not run because no SpecLitmus adapter or minimal executable reproducer was present:
reason: No implementation-specific adapter was present for this candidate.
The runtime evidence did not close the behavior either way.
Inconsistency Reason
A distinguishable mismatch remains plausible for the finite-limit requirement: the endpoint must impose a finite per-connection limit on the number of pre-PTO transmissions of unacknowledged CRYPTO data. Static source review identified the relevant PTO transmission paths, but runtime evidence did not prove whether the optimization can be repeated without a per-connection bound.
Decision Reason
Static source review raised a concrete concern and positive controls passed, but no focused reproducer closed the behavior either way within the runtime budget.
Remaining Uncertainty
Runtime or deeper harness-level evidence is still needed to distinguish the exact packet-number-space, path, timer, congestion-control, key-discard, or undecryptable-packet behavior from the source-only mapping.
Pre-PTO CRYPTO retransmission limits are not fully established
Problem Description
The test cases exercise the same RFC 9002 Section 6.2.4 requirement for a finite per-connection limit on sending unacknowledged CRYPTO data before PTO expiry. Static review left unresolved preconditions, and no implementation-specific executable reproducer was available in the current run.
Standard Requirement
Interpretation: when an endpoint uses the pre-PTO transmission optimization for unacknowledged CRYPTO data, it must impose a finite per-connection limit. It must not apply that optimization an unlimited number of times on one connection.
Relevant Source Code
The requirement was mapped to s2n-quic PTO and congestion-control source categories. The cited source shows the relevant probe transmission mechanism, but static review alone did not close every precondition, cross-state behavior, or runtime observable needed for a conclusion.
quic/s2n-quic-core/src/recovery/pto.rs:17-31PTO timeout handling is the trigger point for sending at least one ack-eliciting probe packet.
quic/s2n-quic-core/src/recovery/pto.rs:95-152PTO probe transmission forces an ack-eliciting PING when no other ack-eliciting frame is present and uses forced transmission interest.
quic/s2n-quic-transport/src/connection/transmission.rs:119-141Normal transmission is constrained by congestion window, while PTO probing switches to
LossRecoveryProbingwith no congestion constraint.quic/s2n-quic-transport/src/recovery/manager.rs:219-276Sent packet accounting excludes ACK-only packets from congestion control, but records congestion-controlled packets, including probes, in sent packet state.
Runtime Evidence
Positive controls were run for representative RTT, PTO, loss, ACK, and persistent-congestion behavior. They passed with exit code
0, showing that the basic recovery test environment was operational.The implementation-specific focused reproducers were not run because no SpecLitmus adapter or minimal executable reproducer was present:
The runtime evidence did not close the behavior either way.
Inconsistency Reason
A distinguishable mismatch remains plausible for the finite-limit requirement: the endpoint must impose a finite per-connection limit on the number of pre-PTO transmissions of unacknowledged CRYPTO data. Static source review identified the relevant PTO transmission paths, but runtime evidence did not prove whether the optimization can be repeated without a per-connection bound.
Decision Reason
Static source review raised a concrete concern and positive controls passed, but no focused reproducer closed the behavior either way within the runtime budget.
Remaining Uncertainty
Runtime or deeper harness-level evidence is still needed to distinguish the exact packet-number-space, path, timer, congestion-control, key-discard, or undecryptable-packet behavior from the source-only mapping.