Skip to content

Commit c5ef53c

Browse files
committed
test(chaos): correct two reporting defects and state what the suite doesn't prove
The hard_cut scenario was labelled "proxy disabled 12s (TCP severed)" with params={"disabled_s": 12}, but it passes fault_hold_s=0.0 and the harness clears the fault the instant detection fires — so the 12s was never applied and the number reached the published record as an unused parameter. Relabelled to what the code actually does. The LATEST.md renderer defaulted a missing ticks_after to 0, which published the baseline row as "Ticks after 0 ... PASS" while that scenario's own note recorded 7 updates in 30s. Absent counts now render as an em dash. Also documents two real limits in CHAOS_TESTING.md that were previously left implicit: the detection-driven scenarios validate recovery against an already-restored network rather than a persistently broken one, and the ticks_after > 0 pass bar is a smoke check on a stream this sparse, not a throughput assertion. The existing run record under docs/chaos/ is annotated rather than rewritten — no recorded measurement is edited, and neither defect changes a pass/fail outcome. Re-running the suite needs a live IG demo session plus toxiproxy, so the corrections are stated against the run that actually happened.
1 parent df5d012 commit c5ef53c

4 files changed

Lines changed: 35 additions & 3 deletions

File tree

docs/CHAOS_TESTING.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ identifiers, or raw log lines — there is nothing to sanitise by design):
7272
- **Host-level chaos** (`iptables` DROP/REJECT, `ss -K`) still exercises the
7373
OS TCP stack in ways a userspace proxy cannot; §9.1's manual run remains
7474
the final pre-live gate.
75+
- **Persistent faults.** The detection-driven scenarios (`silent_stall`,
76+
`hard_cut`) clear the injected fault the moment detection fires, so the
77+
recovery ladder (tear down → REST re-auth → LS rebuild → re-subscribe)
78+
is validated against an *already-restored* network. What these scenarios
79+
prove is that the fault is detected and that the feed streams again
80+
afterwards — not that recovery survives a network still broken while it
81+
runs. Holding the fault across the full ladder, and asserting the retry
82+
backoff behaves while it is held, is the next iteration.
83+
- **Tick-count assertions are weak.** The pass bar for the degradation
84+
scenarios is `ticks_after > 0` against a baseline that produced single-digit
85+
updates per 30 s on these instruments, so a scenario can pass on one tick.
86+
Treat these as smoke-level "did not crash, still streaming" checks rather
87+
than throughput measurements.
7588
- Markets: run against 24/7 instruments (the default epics are crypto) or
7689
during market hours — a closed, tickless market starves the heartbeat and
7790
the suite cannot distinguish injected faults from natural silence.

docs/chaos/LATEST.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,25 @@ Generated 2026-07-12T09:04:07+00:00 against commit `ddac700` (env: `demo`, epics
55
Metrics only — no payloads, tokens, or account identifiers are recorded.
66
See `docs/CHAOS_TESTING.md` for methodology and how to reproduce.
77

8+
> **Corrections to this record (added after the run).** The measurements below
9+
> are unmodified, but two labelling defects in the harness that produced them
10+
> have since been fixed, and this run predates the fix:
11+
>
12+
> 1. The `hard_cut` fault is recorded as *"proxy disabled 12s"*. It was not.
13+
> The scenario passed `fault_hold_s=0.0` and the harness clears the fault
14+
> the instant detection fires, so the proxy was disabled for **9.4 s** here
15+
> (the recorded `detected` time), not a fixed 12 s. The `12` was an unused
16+
> parameter that reached the label. The scenario is now labelled
17+
> *"proxy disabled until heartbeat detection"*.
18+
> 2. The `baseline` row reads *"Ticks after 0"*. That scenario records
19+
> `ticks_baseline_10s`, not `ticks_after`, and the renderer defaulted the
20+
> missing key to `0` — its own note (7 updates in 30 s) is the correct
21+
> figure. Absent counts now render as ``.
22+
>
23+
> Neither defect changes a pass/fail outcome, and no recorded number has been
24+
> edited. See `docs/CHAOS_TESTING.md` → "What this does not cover" for what
25+
> these scenarios do and do not establish.
26+
827
| Scenario | Fault | Detected (s) | Recovered (s) | Ticks after | HB trips | Positions unchanged | Result |
928
|---|---|---|---|---|---|---|---|
1029
| baseline | none ||| 0 | 0 | yes | PASS |

tests/chaos/recorder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def _render_md(self, payload: dict[str, Any]) -> str:
103103
fault=s["fault"],
104104
det="—" if det is None else f"{det:.1f}",
105105
rec="—" if rec is None else f"{rec:.1f}",
106-
ticks=s["counts"].get("ticks_after", 0),
106+
ticks=s["counts"].get("ticks_after", "—"),
107107
trips=s["counts"].get("heartbeat_trips", 0),
108108
pos="yes" if s["positions"].get("unchanged") else "NO",
109109
res="PASS" if s["passed"] else "FAIL",

tests/chaos/test_streaming_chaos.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ async def test_hard_connection_cut_reconnects(
199199
"""
200200
result = await _run_scenario(
201201
name="hard_cut",
202-
fault="proxy disabled 12s (TCP severed)",
203-
params={"disabled_s": 12},
202+
fault="proxy disabled until heartbeat detection (TCP severed)",
203+
params={"hold": "until_detected"},
204204
feed=chaos_feed,
205205
event_log=event_log,
206206
recorder=recorder,

0 commit comments

Comments
 (0)