# Bot Detector IA — Axes d'amélioration

> Suivi d'implémentation — mis à jour le 2025-07-15 | Architecture modulaire (11 modules)

---

## Résumé des axes proposés — État d'implémentation

| # | Axe | Statut | Implémentation |
|---|-----|--------|----------------|
| A1 | [Détection de dérive conceptuelle](#a1--détection-de-dérive-conceptuelle) | ✅ IMPLÉMENTÉ | `scoring.py` : `_compute_drift_score()` + fallback z-score |
| A2 | [Seuil adaptatif par percentile](#a2--seuil-adaptatif-par-percentile) | ✅ IMPLÉMENTÉ | `scoring.py` : `compute_adaptive_threshold()` |
| A3 | [Analyse multi-fenêtres temporelles](#a3--analyse-multi-fenêtres-temporelles) | ✅ IMPLÉMENTÉ | `cycle.py` : `ENABLE_MULTIWINDOW` + `Complet_24h`/`Applicatif_24h` |
| A4 | [Explainabilité par SHAP](#a4--explainabilité-par-shap) | ✅ IMPLÉMENTÉ | `scoring.py` : `_compute_shap_top_features()`, top-5 |
| A5 | [Déduplication avec TTL inter-cycles](#a5--déduplication-avec-ttl-inter-cycles) | ✅ IMPLÉMENTÉ | `cycle.py` : `_filter_recent_detections()`, `DEDUP_TTL_MIN=60` |
| A6 | [Pondération par récurrence dans le score](#a6--pondération-par-récurrence-dans-le-score) | ✅ IMPLÉMENTÉ | `pipeline.py` : `raw -= log1p(count) * RECURRENCE_WEIGHT` |
| A7 | [Validation de complétude des features](#a7--validation-de-complétude-des-features) | ✅ IMPLÉMENTÉ | `scoring.py` : `validate_features()`, `MIN_VALID_FEATURE_RATIO=0.50` |
| A8 | [Clustering comportemental des anomalies](#a8--clustering-comportemental-des-anomalies) | ✅ IMPLÉMENTÉ | `scoring.py` : HDBSCAN + escalade campagne dans `pipeline.py` |
| A9 | [Métriques Prometheus / health check enrichi](#a9--métriques-prometheus--health-check-enrichi) | ❌ À FAIRE | Health check binaire uniquement (`infra.py` : 200/503) |
| A10 | [Normalisation des scores entre modèles](#a10--normalisation-des-scores-entre-modèles) | ✅ IMPLÉMENTÉ | `scoring.py` : `normalize_scores()` min-max [0, 1] |

---

## A1 — Détection de dérive conceptuelle

### ✅ IMPLÉMENTÉ

**Module** : `scoring.py` — fonctions `_compute_drift_score()` et `_compute_drift_score_zscore()`

**Différences avec la proposition initiale** :

| Proposition | Implémentation |
|-------------|----------------|
| KS-test (scipy `ks_2samp`) | Méthode principale : comparaison par quantiles interpolés (KS-like sans scipy). Fallback : z-score `\|μ_current - μ_trained\| / σ_trained > 2.0` |
| Seuil par `p_value < 0.05` | Même seuil p < 0.05 pour la méthode quantile ; z > 2.0 pour le fallback |
| `DRIFT_THRESHOLD` (30%) | ✅ Identique : `DRIFT_THRESHOLD = 0.30` (fraction de features en dérive) |
| Sauvegarde dans `.meta.json` | ✅ `baseline_stats` avec `{mean, std, p25, p75}` par feature |
| Événement `DRIFT_DETECTED` | ✅ Journalisé avec la liste des features déroutantes |

**Appelé depuis** : `models.py` → `load_or_train_model()`, avant la décision de chargement vs retrain.

### Problème

L'Isolation Forest est entraîné sur la baseline humaine courante. Si le profil du trafic légitime évolue graduellement (nouveau navigateur populaire, changement de comportement utilisateur, migration réseau), le modèle vieilli peut :
- Générer des **faux positifs** sur du trafic humain nouvellement apparu
- Rater des **faux négatifs** si les bots imitent les anciens patterns

### Références
- Gama et al. (2014) — *A Survey on Concept Drift Adaptation*
- Rabanser et al. (2019) — *Failing Loudly: An Empirical Study of Methods for Detecting Dataset Shift*

---

## A2 — Seuil adaptatif par percentile

### ✅ IMPLÉMENTÉ

**Module** : `scoring.py` — fonction `compute_adaptive_threshold()`

**Implémentation conforme à la proposition** :

```python
neg_scores = scores[scores < 0]
adaptive = np.percentile(neg_scores, ANOMALY_PERCENTILE)   # défaut : 5
effective_threshold = min(adaptive, ANOMALY_THRESHOLD)      # garde-fou : -0.05
```

| Proposition | Implémentation |
|-------------|----------------|
| `ANOMALY_PERCENTILE` (0–20, défaut 5) | ✅ `config.py` : `ANOMALY_PERCENTILE = 5` |
| Seuil statique en garde-fou | ✅ `ANOMALY_THRESHOLD = -0.05` |
| Log du seuil effectif dans `ANOMALY` | ✅ Journalisé dans les événements |

**Appelé depuis** : `pipeline.py` ligne 144, sur les scores bruts EIF uniquement.

---

## A3 — Analyse multi-fenêtres temporelles

### ✅ IMPLÉMENTÉ

**Module** : `cycle.py` — dans `fetch_and_analyze()`, lignes 257–275

**Implémentation** :

| Proposition | Implémentation |
|-------------|----------------|
| Vue 24h dans ClickHouse | ✅ `MULTIWINDOW_VIEW = 'view_ai_features_24h'` (configurable) |
| Deux modèles supplémentaires | ✅ `Complet_24h` et `Applicatif_24h` |
| Combinaison AND logique | Implémenté en **OR logique** : une IP est flaggée si anomalie dans ≥ 1 fenêtre |
| Score le plus bas conservé | ✅ En cas de doublon, le score le plus bas (le plus anormal) est conservé |
| Activation par feature flag | ✅ `ENABLE_MULTIWINDOW = false` par défaut |

**Note** : La proposition originale suggérait un AND logique (anomalie dans les deux fenêtres). L'implémentation utilise un OR pour maximiser la couverture, avec déduplication par score minimal.

---

## A4 — Explainabilité par SHAP

### ✅ IMPLÉMENTÉ

**Module** : `scoring.py` — fonction `_compute_shap_top_features()`

| Proposition | Implémentation |
|-------------|----------------|
| `TreeExplainer` (sklearn IF) | ✅ Pour sklearn : `shap.TreeExplainer` |
| Top-5 features les plus contributives | ✅ Top-5 features avec valeurs SHAP |
| `ENABLE_SHAP=true/false` | ✅ `config.py` : `ENABLE_SHAP = true` (ET `SHAP_AVAILABLE`) |
| SHAP uniquement sur les anomalies | ✅ Calculé uniquement pour les IPs flaggées |
| Enrichissement du champ `reason` | ✅ Via `_build_reason()` — SHAP intégré dans la raison textuelle |

**Ajout par rapport à la proposition** : Pour isotree (Extended IF), SHAP utilise
`PermutationExplainer` au lieu de `TreeExplainer` (isotree n'est pas nativement
supporté par TreeSHAP).

**Appelé depuis** : `pipeline.py` lignes 298–303, après l'extraction des anomalies.

### Références
- Lundberg & Lee (2017) — *A Unified Approach to Interpreting Model Predictions*

---

## A5 — Déduplication avec TTL inter-cycles

### ✅ IMPLÉMENTÉ

**Module** : `cycle.py` — fonction `_filter_recent_detections()`

| Proposition | Implémentation |
|-------------|----------------|
| `DEDUP_TTL_MIN` (défaut 60 min) | ✅ `config.py` : `DEDUP_TTL_MIN = 60` |
| Requête ClickHouse pour les IPs récentes | ✅ Interroge `ml_detected_anomalies` dans les dernières `DEDUP_TTL_MIN` minutes |
| Variante : réinsertion si dégradation ≥ 0.05 | ✅ Réinsertion uniquement si le score s'est dégradé de ≥ 0.05 points |
| `DEDUP_TTL_MIN=0` pour désactiver | ✅ Conforme |
| Déduplication intra-cycle (`drop_duplicates`) | ✅ `cycle.py` ligne 302 : `drop_duplicates(subset=['src_ip'], keep='first')` |

---

## A6 — Pondération par récurrence dans le score

### ✅ IMPLÉMENTÉ

**Module** : `pipeline.py` — lignes 148–151

| Proposition | Implémentation |
|-------------|----------------|
| `RECURRENCE_WEIGHT = 0.005` | ✅ `config.py` : `RECURRENCE_WEIGHT = 0.005` |
| `adjusted = score - log1p(recurrence) * weight` | ✅ `raw_anomaly_score -= log1p(recurrence_count) * RECURRENCE_WEIGHT` |
| Récurrence chargée depuis ClickHouse | ✅ `view_ip_recurrence` dans `cycle.py` ligne 215 |
| Stockage séparé raw_score / adjusted_score | Le score ajusté remplace `raw_anomaly_score` (pas de stockage séparé) |

---

## A7 — Validation de complétude des features

### ✅ IMPLÉMENTÉ

**Module** : `scoring.py` — fonction `validate_features()`

| Proposition | Implémentation |
|-------------|----------------|
| Détection des features absentes | ✅ Features manquantes du DataFrame |
| Détection des features constantes (std=0) | ✅ Features à std=0 exclues |
| `MIN_VALID_FEATURE_RATIO` (défaut 0.8) | Implémenté à **0.50** (seuil moins strict) |
| Événement `FEATURE_WARNING` | ✅ Journalisé dans le JSONL |
| `SKIPPED_INVALID_FEATURES` si ratio insuffisant | ✅ Retourne `None` → cycle ignoré |

**Ajouts par rapport à la proposition** :
- Détection des features **entièrement à zéro** (pipeline non alimenté) en plus des features constantes.
- Exclusions structurelles par modèle (`STRUCTURAL_EXCLUDED_FEATURES` dans `config.py`) :
  le modèle Applicatif exclut automatiquement 15 features TCP/TLS non disponibles sans corrélation.

---

## A8 — Clustering comportemental des anomalies

### ✅ IMPLÉMENTÉ

**Module** : `scoring.py` — fonction `_cluster_anomalies()` + `pipeline.py` pour l'escalade

| Proposition | Implémentation |
|-------------|----------------|
| DBSCAN (eps=0.5, min_samples=3) | Utilisé en **fallback**. Algorithme principal : **HDBSCAN** |
| `campaign_id` dans les événements | ✅ Journalisé dans les événements `ANOMALY` et inséré dans `ml_detected_anomalies` |
| `eps` et `min_samples` configurables | ✅ `CLUSTERING_MIN_SAMPLES = 3`, `ENABLE_CLUSTERING = true` |
| Activation conditionnelle | ✅ `ENABLE_CLUSTERING` (feature flag) |

**Améliorations par rapport à la proposition** :

1. **HDBSCAN au lieu de DBSCAN** : Utilise `HDBSCAN(min_cluster_size=3, min_samples=2,
   cluster_selection_method='eom')` via import optionnel `hdbscan`. Fallback DBSCAN
   si `hdbscan` non installé.

2. **Clustering dans l'espace latent** : Si un modèle Autoencoder est disponible,
   le clustering opère dans l'espace latent (dimension 16) plutôt que sur les
   features brutes — meilleure séparation des clusters.

3. **Escalade de campagne** (`pipeline.py` lignes 311–324) : Les IPs d'un cluster
   ≥ 5 membres voient leur threat level escaladé de `HIGH` → `CRITICAL`.

### Références
- Ester et al. (1996) — *A Density-Based Algorithm for Discovering Clusters in Large Spatial Databases*
- Campello et al. (2013) — *Density-Based Clustering Based on Hierarchical Density Estimates* (HDBSCAN)

---

## A9 — Métriques Prometheus / health check enrichi

### ❌ À FAIRE

**État actuel** : Le health check est un serveur HTTP binaire dans `infra.py`
(`200 OK` / `503 DEGRADED`). Aucun endpoint `/metrics` n'est exposé.

**Ce qui manque** :
- Endpoint `/metrics` au format Prometheus text
- Métriques : durée du cycle, nombre d'anomalies par modèle, âge du modèle,
  taille de la baseline, score de dérive
- Intégration Grafana/Alertmanager

**Prérequis** : Ajouter `prometheus_client` aux dépendances ou implémenter le
format texte manuellement sur le `HTTPServer` existant.

**Note** : La priorité est faible car les métriques clés sont déjà disponibles via
les événements `CYCLE_END` dans le JSONL et les tables ClickHouse (`ml_all_scores`).

### Proposition originale

Exposer un endpoint `/metrics` sur le même port que le health check :

```
botdetector_cycle_duration_seconds 12.4
botdetector_anomalies_total{model="Complet"} 3
botdetector_model_age_hours{model="Applicatif"} 0.91
botdetector_human_baseline_size{model="Applicatif"} 1725
```

---

## A10 — Normalisation des scores entre modèles

### ✅ IMPLÉMENTÉ

**Module** : `scoring.py` — fonction `normalize_scores()`

| Proposition | Implémentation |
|-------------|----------------|
| Min-max sur les scores < 0 | ✅ Normalisation min-max des scores négatifs |
| Intervalle [-1, 0] | Intervalle **[0, 1]** où 1 = le plus anormal |
| Threat levels sur score normalisé | Les threat levels sont toujours calculés sur le score **brut** IF (`score_to_threat_level()` dans `infra.py`) |
| Déduplication sur score normalisé | La déduplication utilise le score brut ajusté (avec pénalité de récurrence) |

**Note** : Le choix de conserver les threat levels sur le score brut (plutôt que
normalisé) assure la stabilité des seuils de classification. Le score normalisé
est utilisé pour le score final combiné (EIF+AE+XGB) et l'insertion dans
`ml_all_scores`.

---

## Notes d'implémentation générales

- **Compatibilité** : toute amélioration doit rester rétrocompatible avec le schéma `ml_detected_anomalies` existant (ajout de colonnes optionnelles uniquement)
- **Architecture modulaire** : le code est réparti en 11 modules (voir `DOCUMENTATION.md` §1.1), chaque amélioration touche un ou deux modules spécifiques
- **Tests** : 36 tests auto-contenus dans `tests/test_detector.py`, exécutables via `make test-bot-detector`
- **Feature flags** : les fonctionnalités sont activables via variables d'environnement (`ENABLE_SHAP`, `ENABLE_CLUSTERING`, `ENABLE_MULTIWINDOW`, `ENABLE_FEEDBACK`)
- **Imports optionnels** : `isotree`, `torch`, `xgboost`, `shap`, `hdbscan` sont tous optionnels avec fallbacks (`config.py`)

---

# Nouvelles dimensions de features — Propositions B

> Propositions de features supplémentaires pour l'ensemble ML, validées sur les données réelles de `ja4_processing`.
> Chaque proposition indique la force du signal observée en base, la source de données, la formule de calcul et les références scientifiques.

## Résumé des signaux — État d'implémentation

| # | Feature | Statut | Modèle | Implémentation |
|---|---------|--------|--------|----------------|
| B1 | `ja3_diversity_ratio` | ✅ IMPLÉMENTÉ | Complet | `FEATURES_COMPLET` dans `preprocessing.py` ligne 56 |
| B2 | `syn_timing_cv` | ✅ IMPLÉMENTÉ | Complet | `FEATURES_COMPLET` dans `preprocessing.py` ligne 56 |
| B3 | `tls12_ratio` | ✅ IMPLÉMENTÉ | Complet | `FEATURES_COMPLET` dans `preprocessing.py` ligne 56 |
| B4 | `head_ratio` | ✅ IMPLÉMENTÉ | Les deux | `FEATURES` dans `preprocessing.py` ligne 30 |
| B5 | `sec_fetch_absence_rate` | ✅ IMPLÉMENTÉ | Les deux | `FEATURES` dans `preprocessing.py` ligne 30 |
| B6 | `generic_accept_ratio` | ✅ IMPLÉMENTÉ | Les deux | `FEATURES` dans `preprocessing.py` ligne 30 |
| B7 | `http10_ratio` | ✅ IMPLÉMENTÉ | Les deux | `FEATURES` dans `preprocessing.py` ligne 30 |
| B8 | `ip_df_variance` | ✅ IMPLÉMENTÉ | Complet | `FEATURES_COMPLET` dans `preprocessing.py` ligne 56 |
| B9 | IP DF-bit consistency | 🔄 PARTIEL | Complet | Couvert par B8 (`ip_df_variance`), pas de feature séparée |
| B10 | JA4 concentration intra-ASN | ✅ IMPLÉMENTÉ (préexistant) | Les deux | `ja4_asn_concentration` dans `FEATURES` — existait avant les propositions B |

---

## B1 — JA3/JA4 Diversity Ratio (rotation de fingerprint TLS)

### ✅ IMPLÉMENTÉ

**Feature** : `ja3_diversity_ratio` — dans `FEATURES_COMPLET` (modèle Complet uniquement).

**Exclusion structurelle** : Exclue du modèle Applicatif via `STRUCTURAL_EXCLUDED_FEATURES`
dans `config.py`, car le JA3 n'est disponible que pour le trafic corrélé (L4/TLS).

**Détails d'implémentation** :
- La vue ClickHouse `view_ai_features_1h` calcule `uniqMerge(uniq_ja3) / greatest(uniq_ja4, 1)`
- Le MV `mv_agg_host_ip_ja4_1h` agrège `uniqState(ja3)` depuis `http_logs`

### Observation originale

```
185.177.72.60  →  1619 JA3 distincts  /  2 JA4  →  ratio 809.5
194.187.171.160 →  153 JA3 distincts  /  2 JA4  →  ratio 76.5
```

Le JA4 reste stable (il encode le type de client TLS + ALPN) mais le JA3 varie massivement. C'est la signature d'un **bot qui randomise les extensions TLS** pour contourner la détection par fingerprint.

### Références

- Siby et al. (2020) — *Encrypted DNS → Privacy? A Traffic Analysis Perspective*
- Anderson & McGrew (2016) — *Machine Learning for Encrypted Malware Traffic Classification*
- Husák et al. (2022) — *TLS fingerprinting for bot detection*

---

## B2 — SYN-to-ClientHello Timing Regularity

### ✅ IMPLÉMENTÉ

**Feature** : `syn_timing_cv` — dans `FEATURES_COMPLET` (modèle Complet uniquement).

**Implémentation** : Coefficient de variation (std/mean) du timing SYN→ClientHello,
calculé dans la vue ClickHouse : `sqrt(tcp_jitter_variance) / greatest(avg_syn_ms, 1)`.

### Observation originale

```
88.202.237.59 : 45 connexions, avg=22ms, std=0.00ms  → timing robotique parfait
386/3222 IPs analysées (12%) ont une variance=0
```

### Références

- Zeber et al. (2020) — *The Measurement of Web Timing*
- Stevanovic & Pedersen (2015) — *Detecting Bots Using Multi-level Traffic Analysis*

---

## B3 — TLS 1.2 Exclusive Ratio

### ✅ IMPLÉMENTÉ

**Feature** : `tls12_ratio` — dans `FEATURES_COMPLET` (modèle Complet uniquement).

**Utilisation double** : En plus d'être une feature ML, `tls12_ratio` est utilisée
par l'**axe 5 (TLS/TCP Coherence)** de la détection navigateur dans `browser.py`
(condition `tls12_ratio < 0.1` pour un score positif).

### Observation originale

```
95.217.144.244 : 360/360 requêtes en TLS 1.2 (jamais TLS 1.3)
136 IPs utilisent exclusivement TLS 1.2 sur 3259 analysées (4.2%)
```

### Références

- Kotzias et al. (2018) — *Coming of Age: A Longitudinal Study of TLS Deployment*
- Cloudflare Radar 2024 — TLS 1.3 = 95%+ du trafic web mondial

---

## B4 — HEAD Method Ratio

### ✅ IMPLÉMENTÉ

**Feature** : `head_ratio` — dans `FEATURES` (les deux modèles).

**Commentaire dans le code** : `# B4-B7 : features L7 pures` (`preprocessing.py` ligne 29).

### Observation originale

```
34.140.199.84 : 11/12 requêtes HEAD (91.7%) → Google Cloud uptime checker
67/3335 IPs ont >50% de requêtes HEAD
```

### Références

- Barracuda Networks (2023) — *Bot Traffic Report*
- OWASP Automated Threat Handbook — OAT-011: Scraping, OAT-018: Credential Stuffing

---

## B5 — Sec-Fetch Absence Rate

### ✅ IMPLÉMENTÉ

**Feature** : `sec_fetch_absence_rate` — dans `FEATURES` (les deux modèles).

**Utilisation double** : Également utilisée par l'**axe 3 (HTTP Modern)** de la
détection navigateur dans `browser.py` (condition `sec_fetch_absence_rate < 0.3`
pour un score positif, poids 0.25).

### Observation originale

Les headers `Sec-Fetch-*` sont injectés automatiquement par les navigateurs modernes
(Chrome 76+, Firefox 90+). Leur absence signale un client non-navigateur.

### Références

- West & Loshbough (2019) — *Fetch Metadata Request Headers* (W3C Spec)
- Invernizzi et al. (2016) — *CLOAK of Visibility*

---

## B6 — Accept Header Entropy

### ✅ IMPLÉMENTÉ

**Feature** : `generic_accept_ratio` — dans `FEATURES` (les deux modèles).

**Note** : La proposition originale suggérait une entropie du header Accept.
L'implémentation utilise l'approche simplifiée (fraction de requêtes avec Accept
générique/vide), qui est plus robuste et moins coûteuse en calcul ClickHouse.

**Utilisation double** : Également utilisée par l'**axe 3 (HTTP Modern)** dans
`browser.py` (condition `generic_accept_ratio < 0.3`, poids 0.10).

### Références

- Nikiforakis et al. (2013) — *Cookieless Monster*
- Acar et al. (2014) — *The Web Never Forgets*

---

## B7 — HTTP/TLS Protocol Version Mismatch

### ✅ IMPLÉMENTÉ

**Feature** : `http10_ratio` — dans `FEATURES` (les deux modèles).

**Note** : La proposition originale contenait deux features (`http1_tls13_ratio`
et `http10_ratio`). Seule `http10_ratio` (fraction de requêtes HTTP/1.0) a été
implémentée — c'est le signal le plus fort car HTTP/1.0 est extrêmement rare dans
le trafic navigateur moderne.

**Utilisation double** : Également utilisée par l'**axe 5 (TLS/TCP Coherence)** dans
`browser.py` (condition `http10_ratio = 0`, poids 0.15).

---

## B8 — IP DF-Bit Consistency

### ✅ IMPLÉMENTÉ

**Feature** : `ip_df_variance` — dans `FEATURES_COMPLET` (modèle Complet uniquement).

**Implémentation** : `varPop(toFloat64(ip_meta_df))` dans la vue ClickHouse.
La variance du bit DF est combinée avec les features TTL (`avg_ttl`, `ttl_std`)
pour le TCP fingerprinting multi-dimensionnel.

---

## B9 — IP DF-Bit Consistency (proposition distincte)

### 🔄 PARTIEL

**État** : Couvert par B8. La proposition B9 était une variante de B8 avec une
analyse de cohérence intra-session supplémentaire. Cette variante n'a pas été
implémentée séparément — `ip_df_variance` couvre le cas d'usage principal.

---

## B10 — JA4 Concentration intra-ASN

### ✅ IMPLÉMENTÉ (préexistant)

**Feature** : `ja4_asn_concentration` — dans `FEATURES` (les deux modèles).

**Note** : Cette feature existait déjà avant les propositions B, dans la liste
initiale des features du modèle. Elle mesure la concentration d'un même fingerprint
JA4 au sein d'un ASN — un JA4 très concentré dans un seul ASN suggère un outil
déployé dans un datacenter spécifique.

---

## Récapitulatif des modifications ClickHouse réalisées

### Colonnes ajoutées dans `agg_host_ip_ja4_1h`

Les colonnes suivantes ont été ajoutées au MV et à la table d'agrégation pour
supporter les features B1–B8 :

```sql
-- B1 : JA3 diversity ratio
uniq_ja3              AggregateFunction(uniq, String)
-- B2 : SYN timing regularity
avg_syn_ms            SimpleAggregateFunction(avg, Float64)
-- B3 : TLS 1.2 ratio
tls12_count           SimpleAggregateFunction(sum, UInt64)
-- B4 : HEAD method ratio
count_head            SimpleAggregateFunction(sum, UInt64)
-- B5 : Sec-Fetch absence
count_no_sec_fetch    SimpleAggregateFunction(sum, UInt64)
-- B6 : Generic Accept ratio
count_generic_accept  SimpleAggregateFunction(sum, UInt64)
-- B7 : HTTP/1.0 ratio
count_http10          SimpleAggregateFunction(sum, UInt64)
-- B8 : DF-bit variance
ip_df_variance        (calculé via varPop dans la vue)
```

### Features dérivées dans `view_ai_features_1h`

| Feature | Formule | Modèle |
|---------|---------|--------|
| `ja3_diversity_ratio` | `uniqMerge(uniq_ja3) / greatest(uniq_ja4, 1)` | Complet |
| `syn_timing_cv` | `sqrt(tcp_jitter_variance) / greatest(avg_syn_ms, 1)` | Complet |
| `tls12_ratio` | `tls12_count / greatest(hits, 1)` | Complet |
| `head_ratio` | `count_head / greatest(hits, 1)` | Les deux |
| `sec_fetch_absence_rate` | `count_no_sec_fetch / greatest(hits, 1)` | Les deux |
| `generic_accept_ratio` | `count_generic_accept / greatest(hits, 1)` | Les deux |
| `http10_ratio` | `count_http10 / greatest(hits, 1)` | Les deux |
| `ip_df_variance` | `varPop(toFloat64(ip_meta_df))` | Complet |

---

# Fonctionnalités ajoutées hors propositions initiales

> Features et mécanismes implémentés dans la refonte modulaire qui ne figuraient pas
> dans les propositions A1–A10 / B1–B10 originales.

## Ensemble triple-voix (EIF + Autoencoder + XGBoost)

**Module** : `models.py`

La proposition initiale n'incluait qu'un Isolation Forest. L'architecture actuelle
utilise un **ensemble triple-voix** :

| Modèle | Poids | Rôle |
|--------|-------|------|
| Extended Isolation Forest (isotree) | 56% | Détection non supervisée principale |
| Autoencoder (PyTorch) | 24% | Erreur de reconstruction comme signal complémentaire |
| XGBoost | 20% | Supervision via feedback SOC (`soc_feedback`) |

**Formule de combinaison** :

```
final = (1 - β) × [(1 - α) × eif_norm + α × ae_norm] + β × xgb_prob
```

où `α = AE_WEIGHT = 0.30` et `β = XGB_WEIGHT = 0.20`.

## Extended Isolation Forest (isotree)

**Module** : `models.py`

Remplacement de sklearn `IsolationForest` par `isotree.ExtendedIsolationForest` :
- `ndim=min(3, len(features))` — partitions multi-dimensionnelles (contre 1D pour sklearn)
- Calibration des scores : `sklearn_equiv = 0.5 - isotree_score`
- Fallback automatique vers sklearn si `isotree` non installé

## Détection multifactorielle des navigateurs (5 axes)

**Module** : `browser.py`

Nouveau système de classification des navigateurs légitimes basé sur 5 axes
pondérés indépendants (voir `DOCUMENTATION.md` §3.4) :

| Axe | Poids | Signal |
|-----|-------|--------|
| 1 — JA4 Known | 0.25 | Famille navigateur identifiée |
| 2 — JA4 Structure | 0.15 | TLS 1.3, h2/h3, ciphers/extensions |
| 3 — HTTP Modern | 0.25 | Sec-Fetch, Accept-Language, modern_browser_score |
| 4 — Nav Behavior | 0.15 | Cookies, Referer, assets, navigation |
| 5 — TLS Coherence | 0.20 | ALPN, window scale, TLS 1.2 ratio |

Seuil : `browser_confidence ≥ 0.55` + famille identifiée → `LEGITIMATE_BROWSER`.

## Escalade de campagne

**Module** : `pipeline.py` lignes 311–324

Après le clustering HDBSCAN, les IPs appartenant à un cluster de **≥ 5 membres**
voient leur threat level escaladé de `HIGH` → `CRITICAL`. Identifie les campagnes
de botnet coordonnées.

## Feedback SOC (apprentissage supervisé)

**Module** : `cycle.py` lignes 221–238

Intégration du feedback des analystes SOC depuis la table `audit_logs` :
- Faux positifs (FP) → reclassés en baseline humaine (`asn_label='isp'`)
- Vrais positifs (TP) → étiquetés `soc_confirmed_bot` pour l'entraînement XGBoost
- Configurable via `ENABLE_FEEDBACK=true` et `FEEDBACK_WINDOW_DAYS=7`

## Features thèse §5

**Module** : `preprocessing.py` + `cycle.py`

9 features issues de la thèse (§5) enrichies depuis `view_thesis_features_1h` :
- `path_transition_entropy` — entropie des transitions entre chemins
- `cadence_cv` — coefficient de variation de la cadence
- `burst_ratio` / `pause_ratio` — ratios de rafales et pauses
- `lag1_autocorrelation` — autocorrélation lag-1 des inter-arrivées
- `benford_deviation` — déviation par rapport à la loi de Benford
- `host_diversity` / `host_sweep_speed` / `host_coverage_uniformity`

## Features P0+P1 (sous-exploitées et nouvelles)

**Module** : `preprocessing.py`

Features supplémentaires ajoutées à `FEATURES` :
- `is_fake_navigation` — détection de fausse navigation (P0)
- `true_window_size` / `window_mss_ratio` — TCP window analysis (P0, Complet)
- `has_xff` — présence de X-Forwarded-For (P1)
- `unusual_content_type_ratio` — Content-Types inhabituels (P1)
- `non_standard_port_ratio` — ports non standard (P1)
- `login_post_concentration` — concentration de POST sur login (P1)
- `sec_ch_mobile_mismatch` — incohérence Sec-CH-UA-Mobile (P1)

## TTL Fingerprinting OS

**Module** : `preprocessing.py` — `FEATURES_COMPLET`

Features TCP ajoutées pour le fingerprinting du système d'exploitation :
- `avg_ttl` — TTL moyen (différent par OS : 64 Linux, 128 Windows, 255 Cisco)
- `ttl_std` — écart-type du TTL (doit être ~0 pour un trafic homogène)
- `no_window_scale_ratio` — ratio de sessions sans TCP window scaling

## Dérive JA4 intra-session

**Module** : `preprocessing.py` — `FEATURES_COMPLET`

- `ja4_drift_ratio` — fraction de sessions où le JA4 change pendant la session.
  Signal de bot qui reconfigure son client TLS à chaque requête.

## Validation gate (modèles)

**Module** : `models.py`

Après entraînement, le modèle est validé sur un jeu de validation (split 80/20).
Si `val_anomaly_rate > 0.20`, le modèle est rejeté et l'ancien modèle est conservé.
Empêche le déploiement de modèles dégénérés.

## Feature pruning automatique

**Module** : `models.py`

Les features avec variance < 1e-6 sont automatiquement éliminées avant
l'entraînement de l'EIF. Évite les partitions dégénérées sur des features constantes.

