fix(test): robust flowshape check (dense-cluster span) #159

Merged
vxfemboy merged 1 commit from fix/flowshape-cluster-span into main 2026-08-04 00:35:54 +00:00
Owner

What

Fixes the intermittent flowshape_not_obviously_constant failure in the privileged sudo CI job (surfaced on PR #158, issue #157). Independent of #158's content — the sudo job just runs the whole netns suite.

Root cause

The test counted the leading run of handshake datagrams up to the first inter-packet gap > 5ms. That 5ms was calibrated on an idle dev box (intra-burst gaps are microseconds). On the contended CI runner a scheduling stall > 5ms lands mid junk-burst and truncates the run: a ~15–20 datagram burst gets counted as 4–6, tripping gate (a) (> 4). The failing run showed counts 7 12 4 10 8 11 7 19 — half below the structural floor of 9, so this was systematic truncation, not a one-off.

Why no threshold value fixes it

Inspecting real captures: a ~30ms round-trip wait happens inside the handshake, and steady-state feedback (two independent ~30ms streams) produces coincident sub-ms pairs. So gap magnitude alone can't tell which phase a packet is in — any single cutoff either truncates mid-burst or plows into steady state.

Fix

Count the dense-cluster span: the index of the last datagram in a run of ≥3 packets spaced <1ms apart. The handshake is built of such dense clusters (junk bursts, Inits, Noise completion); steady state never forms a ≥3 dense run (only coincident pairs). A scheduling stall can't truncate this — it merely splits one dense cluster into two, both still counted.

Re-derived gate (measured, junk-on vs junk-off, idle + 2× CPU oversubscription)

span
junk-OFF (junk-free dense handshake) 6–10
junk-ON 15–32

Gate (a) is now span > 12 (strictly between). Verified min span 16–17 under load harsher than CI; both gates green. Added a density-valley diagnostic (max intra-cluster vs min separator gap) so any future failure is self-explaining, and deleted the now-dead GAP_THRESHOLD_S.

## What Fixes the intermittent `flowshape_not_obviously_constant` failure in the privileged sudo CI job (surfaced on PR #158, issue #157). Independent of #158's content — the sudo job just runs the whole netns suite. ## Root cause The test counted the **leading run** of handshake datagrams up to the first inter-packet gap > 5ms. That 5ms was calibrated on an idle dev box (intra-burst gaps are microseconds). On the contended CI runner a scheduling stall > 5ms lands mid junk-burst and truncates the run: a ~15–20 datagram burst gets counted as 4–6, tripping gate (a) (`> 4`). The failing run showed counts `7 12 4 10 8 11 7 19` — half below the structural floor of 9, so this was systematic truncation, not a one-off. ## Why no threshold value fixes it Inspecting real captures: a **~30ms round-trip wait happens *inside* the handshake**, and steady-state feedback (two independent ~30ms streams) produces **coincident sub-ms pairs**. So gap magnitude alone can't tell which phase a packet is in — any single cutoff either truncates mid-burst or plows into steady state. ## Fix Count the **dense-cluster span**: the index of the last datagram in a run of ≥3 packets spaced <1ms apart. The handshake is built of such dense clusters (junk bursts, Inits, Noise completion); steady state never forms a ≥3 dense run (only coincident pairs). A scheduling stall can't truncate this — it merely splits one dense cluster into two, both still counted. ## Re-derived gate (measured, junk-on vs junk-off, idle + 2× CPU oversubscription) | | span | |---|---| | junk-OFF (junk-free dense handshake) | 6–10 | | junk-ON | 15–32 | Gate (a) is now `span > 12` (strictly between). Verified min span 16–17 under load harsher than CI; both gates green. Added a density-valley diagnostic (max intra-cluster vs min separator gap) so any future failure is self-explaining, and deleted the now-dead `GAP_THRESHOLD_S`.
fix(test): make flowshape check robust via dense-cluster span, not gap cutoff
Some checks failed
Integration (privileged) / bench-smoke (pull_request) Successful in 3m12s
CI / shear (pull_request) Successful in 3m58s
Integration (privileged) / device-tests (pull_request) Successful in 47s
CI / deny (pull_request) Successful in 7m20s
CI / build-test (pull_request) Successful in 18m9s
Coverage / coverage (pull_request) Successful in 18m57s
Integration (privileged) / netem-comparison (pull_request) Successful in 19m11s
Integration (privileged) / netns-tunnel-test (pull_request) Failing after 24m28s
Integration (privileged) / dpi-undetectability (pull_request) Successful in 21m36s
75bba10b99
The privileged sudo CI job (surfaced on PR #158) intermittently failed
`flowshape_not_obviously_constant`: gate (a) requires each obf-on session's
handshake-phase datagram count > 4, and one session came back 4.

Root cause: the count was the leading run of packets up to the first
inter-packet gap > 5ms. That threshold was calibrated on an idle dev box
where intra-burst gaps are microseconds. On the contended CI runner a
scheduling stall > 5ms lands mid junk-burst and truncates the run — a burst
of ~15-20 datagrams gets counted as 4-6. Diagnosis showed truncation in half
the CI sessions (counts 7,4,8,7 all below the structural floor of 9), not a
one-off.

Inspecting real captures showed no single gap threshold can work: a ~30ms
round-trip wait occurs INSIDE the handshake, and steady-state feedback (two
independent ~30ms streams) produces coincident sub-ms pairs, so gap magnitude
does not identify the phase. The reliable discriminator is cluster density —
the handshake is built of dense runs of >=3 packets <1ms apart; steady state
never forms a >=3 dense run. The count is now the index of the last packet in
such a cluster, which a stall cannot truncate (it only splits one cluster into
two, both still counted).

Re-derived the gate against captured junk-on vs junk-off sessions, idle and
under 2x CPU oversubscription: junk-off spans 6-10 (the junk-free dense
handshake alone), junk-on spans 15-32. Gate (a) is now span > 12. Verified:
min span 16-17 under load harsher than CI, both gates green. Added a
density-valley diagnostic (max intra-cluster vs min separator gap) so any
future failure is self-explaining. Deleted the now-dead GAP_THRESHOLD_S.
vxfemboy deleted branch fix/flowshape-cluster-span 2026-08-04 00:35:55 +00:00
Sign in to join this conversation.
No description provided.