Skip to content

io,ci: drain re-signals BLOCKED frames + auto-retry flaky transfer gate#244

Merged
ch4r10t33r merged 1 commit into
masterfrom
feat/229-231-interop-flake-and-recv-budget
Jul 10, 2026
Merged

io,ci: drain re-signals BLOCKED frames + auto-retry flaky transfer gate#244
ch4r10t33r merged 1 commit into
masterfrom
feat/229-231-interop-flake-and-recv-budget

Conversation

@ch4r10t33r

Copy link
Copy Markdown
Collaborator

Closes #231. Closes #229.

#231 — lost-grant wedge fix + re-enabled delivery-budget test

Root cause of the skipped test's Linux-CI stall: BLOCKED frames are emitted once by the fresh-send path and never retransmitted on loss (only STREAM data has retransmit machinery). When the peer's window-GRANT datagram (MAX_STREAM_DATA/MAX_DATA) is dropped — kernel loopback drop under CI load — after the payload was already accepted into pending_stream_sends, an idle app never re-triggers the fresh-send path, the drain silently skips the closed-window entries, and the transfer wedges forever. This is a real production wedge class (fully-queued reqresp response + app stops writing), not just a harness artifact.

Fix: the pending-send drain (server + client) re-signals STREAM_DATA_BLOCKED / DATA_BLOCKED from its flow-control skip branches, rate-limited to one per 250 ms per conn. The peer answers with a fresh grant; the MAX_DATA/MAX_STREAM_DATA frame arms already re-drain.

  • Re-enabled the skipped raw-app recv delivery budget socket-loopback test (the last open item of recv delivery budget (v1.7.63): follow-ups — recv-side round-robin + re-enable skipped loopback test #231 — recv round-robin + the credit-invariant test landed in 57e1912).
  • New deterministic wedge-recovery test: payload placed directly into the pending queue with conn credit exhausted (exact lost-grant state); completes only via the re-signal path.
  • 301/301 unit tests (0 skips now), stable across 5 repeat runs. The Build and Test job on this very PR exercises the re-enabled test on Linux.

#229 — flaky transfer auto-retry in the interop gate

  • After the three suites, CI re-runs only failed transfer cases once per suite into results-<suite>-retry.json / logs-<suite>-retry. cross-zquic-quinn excluded (its transfer is already KNOWN_FAILING, No per-stream send buffer; partial-frame retransmit pushed onto embedder #184).
  • Summary gate: base-failed + retry-passed → reported as FLAKY-PASSED, non-fatal. A real regression fails both attempts and still reds the gate. Retry logs/json upload with the existing artifact.
  • Verified offline: gate simulation (flaky-passed → exit 0, double-fail → exit 1), retry-detector probe on synthetic results, YAML/bash/python syntax checks.

The #231 drain re-signal plausibly also reduces the #229 flake rate at the source — the same-impl transfer stalls look like exactly this wedge under runner load — but the retry keeps the gate honest either way.

…fer gate (#229)

Two related interop-robustness fixes in one PR.

## Lost-grant wedge + skipped delivery-budget test (#231)

The fresh-send path emits STREAM_DATA_BLOCKED / DATA_BLOCKED once when a
write first gates, but BLOCKED frames are not retransmitted on loss —
only STREAM data has retransmit machinery. If the peer's window-GRANT
datagram (MAX_STREAM_DATA / MAX_DATA) is lost after the payload was
already accepted into `pending_stream_sends`, an idle app never calls
the fresh-send path again, the drain silently skips the closed-window
entries, and the transfer wedges forever. That kernel-loopback drop
under CI load is exactly why the recv-delivery-budget socket-loopback
test stalled intermittently on Linux and was skipped.

Fix: the pending-send drain (server + client) now re-signals
STREAM_DATA_BLOCKED / DATA_BLOCKED from its flow-control skip branches,
rate-limited to one per 250 ms per conn (`blocked_signal_interval_ms`,
`ConnState.blocked_signal_last_ms`). A lost grant self-heals: the peer
answers the re-signal with a fresh MAX_(STREAM_)DATA, whose frame arm
already re-drains.

- Re-enabled the skipped test (`raw-app recv delivery budget` loopback).
- New wedge-recovery test: payload placed directly into
  `pending_stream_sends` with conn credit exhausted (the exact
  lost-grant state — fresh-path emission bypassed); without the
  re-signal it wedges forever, with it the transfer completes via
  DATA_BLOCKED → MAX_DATA → re-drain.

This closes the remaining item of #231 (recv round-robin + the
credit-invariant test landed earlier in 57e1912).

## Flaky transfer gate auto-retry (#229)

The bulk `transfer` testcases intermittently stall on loaded runners —
a DIFFERENT transfer flakes each run on behavior-identical commits.
CI now:

- After the three run.py suites, re-runs ONLY failed `transfer` cases
  once per suite (into `results-<suite>-retry.json` /
  `logs-<suite>-retry`). cross-zquic-quinn is excluded — its transfer
  failure is already KNOWN_FAILING (#184).
- The summary gate classifies a base-failed + retry-passed transfer as
  FLAKY-PASSED (reported, non-fatal). A real regression fails both
  attempts and still reds the gate; retry artifacts upload with the
  rest.

Gate logic simulated both ways (flaky-passed → exit 0; double-fail →
exit 1); retry detector probed on synthetic results; workflow YAML,
step bash, and embedded python all syntax-checked.

301/301 unit tests pass (was 299 + 1 skip: the skip is re-enabled and
one new test added), stable across 5 repeat runs.
@ch4r10t33r ch4r10t33r merged commit bcfdbbc into master Jul 10, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant