mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
With the root pinned, n08's test subject is assertable for the first time: its two candidates sit at equal depth with fiber-grade default netem on one side and Bluetooth on the other, which is exactly the preference this scenario exists to test, and it takes the fiber parent in four of four runs. Encoded as written rather than calibrated from the runs, since "should pick n03" is the spec and the runs merely confirm it is met. n06 is deliberately absent, and its documented criterion is corrected rather than left standing. The header called n03 a fiber parent for n06; the netem policies in the same file say that link is WiFi and the other candidate is Bluetooth, so n06 chooses between two impaired links. Its only fiber-grade link reaches a node at depth 3 that is never a good parent. There was never a reason to expect it to prefer n03, and the two-of-four split observed is correct behaviour: in a run where it took the Bluetooth peer, the fiber-labelled candidate measured a link cost of 3 against the other's 1, so the daemon chose the cheaper effective depth as it should. Validated by replaying the assertion against all four archived runs, then breaking it three ways to confirm it can fail, then one live run for the wiring. One of the breaks expects n06 to take n03 and reports that it chose n02, which is the direct demonstration of why n06 is not encoded. cost-reeval records that its subject now fires in two runs of three, against zero of five when it was structurally impossible, and why that rate is still not one an assertion can rest on.
118 lines
3.9 KiB
YAML
118 lines
3.9 KiB
YAML
# Periodic Cost Re-evaluation Test
|
|
#
|
|
# Topology (explicit 4-node diamond):
|
|
#
|
|
# n01 (root)
|
|
# / \
|
|
# fiber fiber
|
|
# / \
|
|
# n02 n03
|
|
# \ /
|
|
# fiber fiber
|
|
# \ /
|
|
# n04 (test subject)
|
|
#
|
|
# Initial state: All links are fiber. n04 has two candidate parents at
|
|
# depth 1: n02 and n03. Both have identical costs (~1.01), so n04 picks
|
|
# n02 (smaller NodeAddr, tiebreak rule).
|
|
#
|
|
# Mutation: Stochastic netem mutation with a single "degraded" policy
|
|
# (Bluetooth-like: 15-40ms delay, 2-8% loss). With fraction=0.5, on
|
|
# average 2 of 4 edges degrade each round. Over 12 mutation rounds
|
|
# (180s / 15s interval), n02-n04 will be degraded in some rounds.
|
|
#
|
|
# Expected behavior: When n02-n04 is degraded and n03-n04 stays fiber
|
|
# (or vice versa), periodic re-evaluation detects the cost asymmetry
|
|
# and switches parents. Look for "trigger = periodic" in logs.
|
|
#
|
|
# FIPS overrides: reeval_interval_secs=15 (vs default 60) to increase
|
|
# the chance of catching a cost asymmetry within the mutation window.
|
|
#
|
|
# Validation: grep n04 logs for "Parent switched via periodic cost
|
|
# re-evaluation" (trigger=periodic). If mutation never creates enough
|
|
# asymmetry in a particular seed, the test still validates that periodic
|
|
# re-eval runs without interference.
|
|
#
|
|
# THIS SCENARIO COULD NOT EXERCISE ITS SUBJECT AT ALL until 2026-07-23, and
|
|
# the reason is worth keeping because nothing about it was visible from here.
|
|
# The mesh roots at the numerically smallest NodeAddr, a hash of the node's
|
|
# key (src/tree/state.rs:363-390), and that turned out to be **n04** — this
|
|
# scenario's own designated test subject. A root has no parent, and
|
|
# evaluate_parent returns early for the smallest address, so the parent switch
|
|
# described above could never happen. The tree was inverted: n04 at depth 0,
|
|
# n01 a leaf at depth 2, in all five recent runs.
|
|
#
|
|
# The archived logs show exactly that shape. The live info! string above
|
|
# appears in 14 of 105 historical runs, on n04 in 13 of them, back when keys
|
|
# were regenerated per run and the root wandered. In the five runs before this
|
|
# fix it appears only on **n01** — the node that actually had a parent choice.
|
|
#
|
|
# `topology.pin_root` (default true) now assigns identities in NodeAddr order
|
|
# so n01 is root and n04 is the depth-1 subject this file describes.
|
|
#
|
|
# MEASURED after the fix, 2026-07-23: the periodic switch now happens, in 2 of
|
|
# 3 runs on n04 (0, 1, 1 occurrences). Before the fix it was 0 in 5 of 5, and
|
|
# structurally impossible rather than merely rare. So the subject is exercised
|
|
# for the first time.
|
|
#
|
|
# STILL NOT ASSERTED, deliberately. A "at least one periodic switch" assertion
|
|
# would red roughly one run in three on this evidence, and a single run reading
|
|
# zero is an argument against asserting rather than for it. Two ways forward,
|
|
# neither taken here: gather enough runs to know whether 2-in-3 is the real
|
|
# rate, or reduce the variance -- the mutation is stochastic with fraction=0.5,
|
|
# so a deterministic link-degradation schedule would make the asymmetry this
|
|
# scenario needs occur every run and the outcome assertable.
|
|
# Tracked in ISSUE-2026-0085.
|
|
|
|
scenario:
|
|
name: "cost-reeval"
|
|
seed: 42
|
|
duration_secs: 180
|
|
|
|
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 baseline
|
|
delay_ms: [1, 5]
|
|
jitter_ms: [0, 1]
|
|
loss_pct: [0, 0.5]
|
|
mutation:
|
|
interval_secs: {min: 12, max: 18}
|
|
fraction: 0.5
|
|
policies:
|
|
degraded:
|
|
delay_ms: [15, 40]
|
|
jitter_ms: [5, 15]
|
|
loss_pct: [2, 8]
|
|
|
|
link_flaps:
|
|
enabled: false
|
|
|
|
traffic:
|
|
enabled: true
|
|
max_concurrent: 1
|
|
interval_secs: {min: 15, max: 30}
|
|
duration_secs: {min: 5, max: 10}
|
|
parallel_streams: 2
|
|
|
|
logging:
|
|
rust_log: "info"
|
|
output_dir: "./sim-results"
|
|
|
|
fips_overrides:
|
|
node:
|
|
tree:
|
|
reeval_interval_secs: 15
|