chore: add .gitignore

This commit is contained in:
dom
2026-03-05 00:37:41 +01:00
parent 542797a124
commit 2578afb6ff
1716 changed files with 1905609 additions and 18 deletions

171
docs/NUKE3_NEXT_STEPS.md Normal file
View File

@@ -0,0 +1,171 @@
# NUKE-3 — Plan de sprint court
## 3 Objectifs
1. **Réduire le taux REVIEW sur les dossiers sans DP** : 43/43 → cible < 50% REVIEW
2. **Améliorer la qualité du pool** : éliminer le bruit OCR et fusionner les doublons
3. **Activer le signal synthèse** : rendre motif_align opérant même sur les dossiers trackare
## 5 Patchs proposés (ordre d'impact)
### Patch 1 — Dedup par code dans `build_candidates()` ⭐⭐⭐
**Symptôme** : Même code CIM-10 apparaît 2× (edsnlp + regex) → le candidat se bat contre lui-même, delta artificiellement réduit.
**Patch minimal** : `src/medical/dp_selector.py`, fonction `build_candidates()`
```python
# Après la boucle de construction des candidats :
# Dedup par code : garder le meilleur section_strength, ajouter bonus multi-source
seen: dict[str, DPCandidate] = {}
for c in candidates:
if not c.code:
continue
if c.code in seen:
existing = seen[c.code]
existing.num_occurrences += 1
if c.section_strength > existing.section_strength:
existing.section_strength = c.section_strength
existing.source = c.source
else:
seen[c.code] = c
candidates = list(seen.values())
# Réindexer
for i, c in enumerate(candidates):
c.index = i
```
**Pourquoi ça aide** : Les 4 dossiers avec doublons (I26.9, K81.0, D69.6, J18.9) gagnent un candidat fusionné plus fort. Le bonus `occurrences` existant (+1 ou +2) s'active déjà sur `num_occurrences`.
**Test** : `test_dedup_same_code_merged()` — 2 candidats avec même code, sources différentes → 1 seul candidat avec meilleur section_strength.
**Effort** : 1h
---
### Patch 2 — Filtre bruit OCR dans `build_candidates()` ⭐⭐⭐
**Symptôme** : Candidats avec texte OCR corrompu ("C : 9.4", "C omprend décollement de la (d") polluent le pool et consomment des places dans top_k=7.
**Patch minimal** : `src/medical/dp_selector.py`, dans `build_candidates()`
```python
MIN_TERM_WORDS = 2
def _is_ocr_noise(text: str) -> bool:
"""Rejette les candidats dont le texte est du bruit OCR."""
clean = text.strip()
if len(clean) < 4:
return True
words = clean.split()
if len(words) < MIN_TERM_WORDS:
return True
# Ratio de caractères non-alpha suspect
alpha = sum(1 for ch in clean if ch.isalpha())
if alpha / max(len(clean), 1) < 0.5:
return True
return False
```
**Pourquoi ça aide** : Réduit le pool de 7 à ~4-5 candidats pertinents, améliore le delta.
**Test** : `test_ocr_noise_excluded()` — candidat "C : 9.4" exclu du pool.
**Effort** : 1h
---
### Patch 3 — Synthèse depuis top-level JSON + sections trackare ⭐⭐
**Symptôme** : 100% des REVIEW ont synthèse vide → `motif_align` ne fonctionne jamais. Le JSON a `sejour.motif` mais `build_synthese()` ne lit que `sections.motif_hospitalisation`.
**Patch minimal** : `src/medical/dp_selector.py`, fonction `build_synthese()`
```python
def build_synthese(dossier, parsed_data):
sections = parsed_data.get("sections", {})
motif = sections.get("motif_hospitalisation", "")
conclusion = sections.get("conclusion", "")
# Fallback : motif depuis le séjour (trackare)
if not motif and dossier.sejour.motif:
motif = dossier.sejour.motif
return {"motif": motif, "conclusion": conclusion, ...}
```
**Pourquoi ça aide** : Active le bonus `motif_align` (+2) sur les trackare qui stockent le motif dans `sejour.motif`, discriminant les candidats.
**Test** : `test_synthese_fallback_sejour_motif()` — synthèse avec motif depuis séjour.
**Effort** : 30min
---
### Patch 4 — Abaisser DELTA_CONFIRMED de 3.0 à 2.0 ⭐⭐
**Symptôme** : 13/43 REVIEW ont delta 2.0-2.9 — cas où le pré-ranker a une préférence nette mais pas assez pour le seuil actuel. Exemple : T83.5 (4.0) vs R50.9 (2.0) = delta 2.0 → REVIEW, alors que le symptôme (R50.9) est clairement un mauvais DP.
**Patch minimal** : `src/medical/dp_selector.py`
```python
DELTA_CONFIRMED = 2.0 # Était 3.0
```
**Pourquoi ça aide** : +13 CONFIRMED (30% des REVIEW), mais uniquement si les gardes A1/A2/A3 valident. Le hardening empêche les faux positifs.
**Test** : Adapter les fixtures existantes (dp_acute_vs_comorbidity.json utilise un delta attendu).
**Effort** : 30min (+ vérification non-régression)
---
### Patch 5 — DAS order bonus (premier listé = plus saillant) ⭐
**Symptôme** : En cas d'ex-aequo total (15 cas), il n'y a aucun signal pour départager. Or l'ordre des DAS dans le document médical n'est pas aléatoire — les premiers listés sont souvent les plus pertinents.
**Patch minimal** : `src/medical/dp_selector.py`, dans `score_candidates()`
```python
# 9. Bonus d'ordre (premier DAS listé = +1)
if c.index == 0:
score += 1
details["first_listed"] = 1
elif c.index == 1:
score += 0.5
details["second_listed"] = 0.5
```
**Pourquoi ça aide** : Brise les ex-aequo dans 15 cas (36% des REVIEW) avec un signal faible mais non-arbitraire. Le premier DAS listé reflète l'ordre du document source.
**Test** : `test_first_listed_bonus()` — 2 candidats identiques, le premier listé gagne.
**Effort** : 30min
---
## Ordre d'exécution
| # | Patch | Effort | Impact estimé | Pré-requis |
|---|-------|--------|---------------|------------|
| 1 | Dedup par code | 1h | 4 dossiers améliorés | Aucun |
| 2 | Filtre bruit OCR | 1h | ~5 dossiers pool nettoyé | Aucun |
| 3 | Synthèse fallback | 30min | Jusqu'à 43 dossiers (si motif trackare dispo) | Vérifier séjour.motif |
| 4 | DELTA 3.0 → 2.0 | 30min | +13 CONFIRMED | Patches 1+2 (pool propre) |
| 5 | DAS order bonus | 30min | Brise 15 ex-aequo | Après patch 4 |
**Total estimé** : 3h30
## Critères d'acceptation (KPI)
| KPI | Avant | Cible |
|-----|-------|-------|
| REVIEW rate (sans-DP) | 100% (43/43) | < 50% |
| CONFIRMED + evidence | 100% | 100% (maintenu) |
| DP symptôme R* (CONFIRMED) | 0% | < 5% |
| DP comorbidité (CONFIRMED) | 0% | < 3% |
| Candidats bruit OCR dans pool | ~5% | 0% |
| Ex-aequo (delta=0) | 36% (15/43) | < 15% |
## Prochaines étapes hors sprint
- **Gold standard CRH** : sélectionner 20 CRH avec DP expert pour mesurer `confirmed_accuracy`
- **Benchmark LLM ON** : relancer le pipeline avec `T2A_DP_RANKER_LLM=1` sur les 43 REVIEW
- **Extraction synthèse trackare** : parser le motif d'hospitalisation depuis les PDF trackare
---
*Plan rédigé le 2026-02-24 — benchmark offline sur 249 dossiers*