mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
cost-avoidance and mixed-technology decide a parent by measured link cost (etx * (1 + srtt_ms/100)). Under the local CI's 4-way-parallel chaos the fast fiber link's measured srtt spikes from host scheduling and can exceed the Bluetooth link's, flipping the choice and reddening a run that proves nothing about the daemon. The old margin was ~0.4 cost units, which a ~24ms one-sided scheduling blip closes. Widen the Bluetooth delay to 150-250ms so the margin dwarfs any plausible one-sided spike. The link still establishes well within the handshake budget (a ~500ms RTT against a 30s stale-handshake window), so the losing candidate is still a real, established peer rather than an absent one. Add a netem mutation exclude_edges option and use it in mixed-technology to pin the two links n08 chooses between, so a random degradation can't flip the asserted comparison either. An unknown excluded edge is a hard error, since a silent no-op would reintroduce the flakiness it exists to remove. Validated by running both scenarios repeatedly under heavier-than-CI concurrent load: the parent choice holds every time.
97 lines
3.1 KiB
YAML
97 lines
3.1 KiB
YAML
# Cost-Based Parent Selection: Bottleneck Avoidance Test
|
|
#
|
|
# Topology (explicit 4-node diamond):
|
|
#
|
|
# n01 (root — smallest addr)
|
|
# / \
|
|
# fiber fiber
|
|
# / \
|
|
# n02 n03
|
|
# \ /
|
|
# BT fiber
|
|
# \ /
|
|
# n04 (test subject)
|
|
#
|
|
# n04 has two candidate parents at depth 1: n02 (via Bluetooth L2CAP)
|
|
# and n03 (via fiber). Cost-based selection should pick n03 because
|
|
# link_cost = etx * (1 + srtt_ms/100), so the far slower Bluetooth link
|
|
# costs far more:
|
|
# effective_depth(n02) = 1 + ~4.5 (Bluetooth, ~150-250ms) = ~5.5
|
|
# effective_depth(n03) = 1 + ~1.05 (fiber, ~1-5ms) = ~2.05
|
|
#
|
|
# The Bluetooth delay was widened deliberately, and the size is set by load,
|
|
# not by realism. At the original 15-40ms the cost margin was ~0.4, and even
|
|
# 80-120ms was not enough: under the CI's parallel-chaos contention the
|
|
# *measured* srtt of the fiber link spikes (host scheduling, not netem) and
|
|
# was observed to exceed a 120ms Bluetooth base, flipping n04 to n02. At
|
|
# 150-250ms the gap dwarfs any plausible one-sided fiber spike, so the
|
|
# assertion below is a reliable verdict rather than a coin toss under load.
|
|
# n04 still establishes the n02 link (it was parented to it when this flaked),
|
|
# so the choice remains real rather than vacuous.
|
|
#
|
|
# Validation: tree snapshot shows n04's parent is n03.
|
|
|
|
scenario:
|
|
name: "cost-avoidance"
|
|
seed: 42
|
|
duration_secs: 45
|
|
|
|
topology:
|
|
algorithm: explicit
|
|
num_nodes: 4
|
|
params:
|
|
adjacency:
|
|
- [n01, n02]
|
|
- [n01, n03]
|
|
- [n02, n04]
|
|
- [n03, n04]
|
|
subnet: "172.20.0.0/24"
|
|
ip_start: 10
|
|
|
|
netem:
|
|
enabled: true
|
|
default_policy:
|
|
# Fiber-like
|
|
delay_ms: [1, 5]
|
|
jitter_ms: [0, 1]
|
|
loss_pct: [0, 0.5]
|
|
link_policies:
|
|
# Bluetooth (L2CAP) link from n02 to n04. Delay widened to 150-250ms so the
|
|
# fiber-vs-Bluetooth cost margin survives CI load spikes on the fiber
|
|
# probe's measured latency (see header). Well within handshake timeouts, so
|
|
# the n02 link still establishes and the choice stays real.
|
|
- edges: ["n02-n04"]
|
|
policy:
|
|
delay_ms: [150, 250]
|
|
jitter_ms: [15, 30]
|
|
loss_pct: [2, 8]
|
|
|
|
link_flaps:
|
|
enabled: false
|
|
|
|
traffic:
|
|
enabled: true
|
|
max_concurrent: 2
|
|
interval_secs: {min: 15, max: 30}
|
|
duration_secs: {min: 5, max: 10}
|
|
parallel_streams: 2
|
|
|
|
# The validation line at the top of this file, encoded. It existed only as
|
|
# that comment and was checked by nothing, so the scenario could not fail
|
|
# on the one thing it was built to test.
|
|
#
|
|
# From the archived corpus: of the six runs that carry a status.txt and are
|
|
# therefore provably completed, n04's parent is n03 in all six. Among the
|
|
# 176 older runs the picture is quite different -- n04 is absent from the
|
|
# snapshot in 107 of them and is its own root in 49 -- but those are runs
|
|
# whose tree had not converged when the snapshot was taken rather than runs
|
|
# that chose the wrong parent, which is why the assertion fails an absent
|
|
# or self-parented node explicitly instead of skipping it.
|
|
assertions:
|
|
tree_parents:
|
|
n04: n03
|
|
|
|
logging:
|
|
rust_log: "info"
|
|
output_dir: "./sim-results"
|