Skip to content

fix: keep idle traffic from collapsing adaptive pacing - #20

Merged
cppla merged 2 commits into
mainfrom
codex/adaptive-pacing-idle-samples
Sep 22, 2026
Merged

cppla merged 2 commits into
mainfrom
codex/adaptive-pacing-idle-samples

Conversation

@cppla

@cppla cppla commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

Fix native QUIC adaptive pacing treating ACK/control traffic during application-send silence as low outbound capacity. This was reproducible when receiving an upload and then sending a download on the same connection.

  • Track cumulative application-send idle time across stream writes and datagram batches on one connection.
  • Keep pacing waits and transport-blocked writes active; serialize transport snapshots without holding the connection-pacer lock across admission or I/O.
  • Rebaseline predominantly idle samples only when idle time spans both a stable sample window and at least half the interval. Preserve target/history while still observing mostly busy intervals with short source gaps.
  • Preserve fixed-rate and bypass semantics, cancellation, stream deadlines, and transport-owned congestion control.
  • Document the approximate filter and evidence boundaries; no protocol, dependency, version or release changes.

Verification

  • Local make check and make race: passed on the final source.
  • Local make stealth-tools-check: passed; no capture campaign was run.
  • Deterministic regressions cover ACK-only idle intervals, accumulated sub-window idle, short gaps, resets, invalid counters, and resumed or predominantly busy capacity/loss/RTT changes.
  • Stream/datagram activity tests cover blocked admission/I/O, cancellation, partial writes, empty/closed writes, and shared activity.
  • Real loopback QUIC adapter/controller regression: repeated ordinary and race passes, target retained at 8,000,000 bytes/s after receive-only intervals, byte-for-byte upload/download/trailer checks.
  • Focused negative control disabling only the adapter's idle signal fails the same regression: 8,000,000 -> 65,536 bytes/s. This is not presented as a full historical build.
  • Final bounded same-client diagnostic: 4 MiB upload plus 4 MiB download and their acknowledgements completed in 9.41 s. The previous diagnostic timed out during the download payload at a 12 s overall deadline.

Limits

The last item is one local diagnostic, not a throughput benchmark. Download still slowed toward the end; healthy overall adaptive throughput is not established. The focused integration fixture exercises the real QUIC adapter/controller, not authentication/serverCore. No passive-traffic, browser-equivalence, remote-host, or comparative-performance conclusion is claimed. Raw diagnostics remain local and are not included in this PR.

Exact-head CI

Head 0d7637ab6035c9489e18e9961fef40a4b02c7ab7:

  • CI: passed, including Linux/macOS tests, race, vulnerability scan, all cross-builds, real container integration and OCI index build.
  • CodeQL: passed.
  • Linux netem: passed, including the namespace/netem suite.

Independent code, scope and secret reviews found no remaining blocker.

Post-merge verification

Merged as 57e431f495444147b7e6d048ad3c6bdb586e0217. The merge tree exactly matches the verified PR head (9652abd909ba7e99076897814eb321666f57b920).

The local checkout is synchronized with main. No tag or release was created.

Copilot AI lite review requested due to automatic review settings September 22, 2026 13:41
@cppla
cppla merged commit 57e431f into main Sep 22, 2026
14 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Address the datagram deadline checks and clarify the cumulative-idle architecture wording.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Medium severity · 1 Low severity

Open (2)
What changed in this PR

This PR updates native QUIC adaptive pacing to account for connection-wide application-send idle time, preventing ACK/control traffic from appearing as low outbound capacity.

Changes:

  • Tracks stream and datagram write activity across pacing and transport waits.
  • Filters predominantly idle adaptive samples while preserving active behavior.
  • Adds regression coverage and documentation.
File Summary Final review note
internal/​tunnel/​quic.go Tracks stream write activity. —
internal/​tunnel/​pacing.go Tracks activity and observes idle time. —
internal/​tunnel/​pacing_write_activity_test.go Tests stream activity lifecycle. —
internal/​tunnel/​pacing_idle_integration_test.go Adds loopback QUIC regression coverage. —
internal/​tunnel/​pacing_datagram_activity_test.go Tests datagram activity and cancellation. —
internal/​tunnel/​pacing_activity_test.go Tests shared idle accounting. —
internal/​tunnel/​datagram.go Tracks datagram batch activity. Moderate: use contextError for both deadline guards.
internal/​accel/​pacing_idle_test.go Tests idle filtering and recovery. —
internal/​accel/​pacer.go Adds cumulative idle-aware filtering. —
docs/​ARCHITECTURE.md Documents native pacing behavior. Nit: clarify that idle time is cumulative across a stable window.
docs/​ACCELERATION.md Documents idle-filter semantics. —

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +998 to +1000
if err := context.Cause(queued.ctx); err != nil {
return err
}
Comment thread docs/ARCHITECTURE.md
Comment on lines +209 to +210
Intervals that are at least half idle, with a stable sampling window of no
pending sends, are rebaselined instead of turning ACK-only traffic into a low
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants