@@ -57,6 +57,18 @@ For the first configured benign hours, the module does **fit-only** (Welford onl
5757- no detection decisions are emitted from hourly z-score rules before training ends,
5858- baseline mean/variance are learned strongly from this period.
5959
60+ Training fit strength is configurable with ` training_alpha ` :
61+
62+ Training fit technique is selected by ` training_fit_method ` :
63+
64+ - ` training_fit_method = welford ` -> Welford benign fit.
65+ - ` training_fit_method = ewma ` -> EWMA-style training adaptation.
66+
67+ When ` training_fit_method = ewma ` , ` training_alpha ` controls strength:
68+
69+ - higher ` training_alpha ` = faster adaptation,
70+ - lower ` training_alpha ` = slower adaptation.
71+
6072### No explicit training (` training_hours = 0 ` )
6173
6274Detection starts immediately using online adaptation.
@@ -67,19 +79,53 @@ Special fallback only for `ja3_changes`:
6779
6880## Scoring
6981
70- Each modeled feature uses z-score:
82+ Each modeled feature uses robust scoring in three explicit steps:
83+
84+ 1 . Transform heavy-tail signals: ` y = log(1 + x) ` (` log1p ` ) for non-negative count/bytes features.
85+ 2 . Estimate robust center/scale on recent transformed values:
86+ - ` m = median(y) `
87+ - ` MAD = median(|y - m|) `
88+ - ` sigma_robust = max(1.4826 * MAD, min_std_floor) `
89+ 3 . Score deviation:
90+ - ` z_robust = |y_t - m| / sigma_robust `
7191
72- - ` z = |x - mean| / std_effective `
73- - ` std_effective ` uses variance with a robust minimum floor to avoid unstable near-zero std.
92+ Why this is used:
93+
94+ - HTTPS counts and byte volumes are typically right-skewed and heavy-tailed,
95+ - mean/std-only scoring overreacts to bursts and underreacts after outliers,
96+ - ` log1p + median/MAD ` is more stable under non-Gaussian traffic.
7497
7598Thresholds:
7699
77- - ` hourly_zscore_threshold ` for hourly features
78- - ` flow_zscore_threshold ` for flow bytes to known servers
100+ - empirical thresholds calibrated from benign training when ` training_hours > 0 ` ,
101+ - otherwise defaults (` hourly_zscore_threshold ` , ` flow_zscore_threshold ` ).
102+
103+ Calibration rule:
104+
105+ - per signal, collect robust z-scores on confirmed benign training data,
106+ - set threshold to high benign quantile (` empirical_threshold_quantile ` , default 0.995),
107+ - fallback to defaults if training data is insufficient.
79108
80109## Adaptation states
81110
82- After each hour closes, the module chooses model update mode:
111+ After each hour closes, the module chooses model update mode.
112+
113+ Update event semantics:
114+
115+ - ` training_fit ` :
116+ initial benign baseline fit while ` trained_hours < training_hours ` ;
117+ uses training fit method (Welford-style), not EWMA alpha.
118+ - ` baseline_update ` :
119+ normal post-training adaptation; uses EWMA with ` baseline_alpha ` .
120+ In ADWIN mode, this is used when ADWIN does not signal drift.
121+ - ` drift_update ` :
122+ post-training drift adaptation; uses EWMA with ` drift_alpha ` .
123+ In ADWIN mode, this is used only after ADWIN drift signal and small/drift-like classification.
124+ - ` suspicious_update ` :
125+ post-training conservative adaptation; uses EWMA with ` suspicious_alpha ` .
126+ In ADWIN mode, this is used only after ADWIN drift signal and suspicious classification.
127+
128+ When ` use_adwin_drift=false ` :
83129
841301 . ` training_fit `
85131 During benign training: Welford fit (no EWMA alpha).
@@ -92,14 +138,14 @@ After each hour closes, the module chooses model update mode:
92138
93139For normal non-anomalous periods outside training, per-feature EWMA uses ` baseline_alpha ` .
94140
95- ### Optional ADWIN drift trigger
141+ ### ADWIN drift trigger ( ` use_adwin_drift=true ` )
96142
97- If ` use_adwin_drift=true ` and ` river ` is installed, ADWIN is used as drift trigger in both paths:
143+ If ` use_adwin_drift=true ` and ` river ` is installed, ADWIN is the only drift trigger in both paths:
98144
99- - ** Hourly path** : ADWIN receives ` hourly_adwin_score ` (sum of hourly feature z-scores) .
100- - ** Flow path** : ADWIN receives ` flow_score ` (sum of reason z-scores, novelty reasons mapped to a small fixed score) .
145+ - ** Hourly path** : ADWIN receives each raw hourly feature stream .
146+ - ** Flow path** : ADWIN receives each raw per-flow signal stream .
101147- ADWIN drift detected -> classify as ` drift_update ` or ` suspicious_update ` using existing thresholds.
102- - No ADWIN drift -> use ` baseline_update ` (` baseline_alpha ` ).
148+ - No ADWIN drift -> use ` baseline_update ` (` baseline_alpha ` ), even if anomalies exist .
103149- During benign training, ADWIN is still warmed with benign scores to reduce cold-start noise after training.
104150
105151Why raw signals:
@@ -113,6 +159,13 @@ Performance note:
113159- flow ADWIN cost scales with per-flow signal count,
114160- both are constant-time scalar updates and usually lightweight.
115161
162+ Current tuned defaults for faster ADWIN reaction:
163+
164+ - ` adwin_delta: 0.01 `
165+ - ` adwin_clock: 1 `
166+ - ` adwin_grace_period: 5 `
167+ - ` adwin_min_window_length: 5 `
168+
116169## New server vs JA3 behavior
117170
118171- ` new_servers ` is modeled as an hourly statistical feature and adapted over time.
@@ -158,6 +211,8 @@ Section: `anomaly_detection_https` in `config/slips.yaml`.
158211Main keys:
159212
160213- ` training_hours `
214+ - ` training_fit_method `
215+ - ` training_alpha `
161216- ` hourly_zscore_threshold `
162217- ` flow_zscore_threshold `
163218- ` adaptation_score_threshold `
@@ -172,13 +227,24 @@ Main keys:
172227- ` adwin_clock `
173228- ` adwin_grace_period `
174229- ` adwin_min_window_length `
230+ - ` empirical_threshold_quantile `
175231- ` log_verbosity `
176232
177- Default: ` use_adwin_drift=true ` .
233+ Defaults (from parser/config):
234+
235+ - ` training_alpha: 1.0 `
236+ - ` training_fit_method: welford `
237+ - ` use_adwin_drift: true `
238+ - ` adwin_delta: 0.01 `
239+ - ` adwin_clock: 1 `
240+ - ` adwin_grace_period: 5 `
241+ - ` adwin_min_window_length: 5 `
178242
179243Reference:
180244
181245- River ADWIN: https://riverml.xyz/latest/api/drift/ADWIN/
246+ - Data transformations for skew/heavy tails: https://otexts.com/fpp3/transformations.html
247+ - Robust scale (MAD): https://en.wikipedia.org/wiki/Median_absolute_deviation
182248
183249## Operational logs
184250
0 commit comments