- Prompt DAS_EXTRACTION : ajout consignes anti-hallucination (zero invention,
pas d'inférence de comorbidités, exiger citation exacte du texte)
- Prompt CODING_CIM10 : ajout consignes conditionnel et négation
- diagnostic_extraction.py : détection de négation avant les patterns regex DAS
(bloque "pas d'embolie", "absence de sepsis", "sans signe d'IRC", etc.)
- veto_engine.py : VETO-03 conditionnel cherche maintenant PRÈS du concept
(40 chars), "si" isolé ne déclenche plus de faux positif, ajout cues
(possible, risque de, aspect de, à confirmer, à rechercher)
- veto_engine.py : négation enrichie (ne retrouve pas, sans signe/argument,
écarté, infirmé, pas mis en évidence)
Batch analysis: VETO-02 63% from LLM hallucinations, VETO-03 63% false positives
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Script build_coding_dict.py génère le dictionnaire depuis le batch (240 dossiers)
- coding_dictionary.json : co-occurrences DP→DAS, fréquences, associations bio
- anomaly_stats.py : 8 checks (DP/DAS rare, DAS manquant, bio-DAS, âge atypique)
- Intégré dans le pipeline cim10_extractor post-DIM-senior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Nouveau module rules_manager.py : CRUD YAML pour les regles metier
- Nouveau blueprint bp_rules.py + template admin_rules.html :
interface web pour activer/desactiver/ajouter/supprimer des regles
- Extraction helpers.py depuis app.py (filtres Jinja2, statistiques,
scan dossiers, status systeme) — app.py passe de 1585 a 482 lignes
- Suppression backward-compat re-exports dans cim10_extractor et
cpam_response (imports corriges dans les tests)
- README.md : architecture, modules, installation, utilisation
- pyproject.toml : dependencies completes, config ruff, pytest, coverage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Le LLM générait des tags génériques [BIO-N], [TRT-N] au lieu des vrais tags du dossier,
causant des warnings "preuve non traçable". Corrigé en 3 points :
- cpam_context: liste exhaustive des tags disponibles injectée dans le prompt
- templates: remplacement des patterns génériques par {tags_disponibles_str}
- cpam_validation: guardian step 4b résout les tags génériques résiduels
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- DIAGNOSIS_ALIASES : mapping acronymes cliniques → CIM-10 (DLBCL→C83.3, SCA→I25.1, EP→I26.9, IDM→I21.9, etc.)
- Scoring 4b étendu : conclusion (+2) ajouté aux sections diagnostiques, matching par alias en plus du terme/code
- _collect_evidence : détection alias dans les sections pour preuves plus complètes
- Garde-fou Trackare : si DP est un R-code (symptôme) et que les sections CRH mentionnent un diagnostic étiologique via alias → verdict REVIEW au lieu de CONFIRMED, alerte DIM
- Case 74 : verdict attendu REVIEW (conclusion mentionne les 2 diagnostics, delta insuffisant)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- crh_parser: 3 nouvelles sections (diag_sortie, diag_principal, synthese)
avec garde-fou début de ligne pour éviter faux positifs mid-sentence
- dp_selector: NUKE-3 sélecteur DP déterministe (548 lignes)
- build_candidates/score_candidates/select_dp
- bonus +4 pour mention dans diag_sortie/diag_principal
- bonus +2 pour mention dans synthese
- hardening DIM : A1 evidence, A2 mono-fragile, A3 confidence cap
- _collect_evidence match par terme OU code CIM-10
- LLM tiebreaker optionnel (DP_RANKER_CONSTRAINED)
- fusion: propagation dp_selection depuis le dossier source du DP retenu
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CPAM : badge quality_tier (A/B/C), bandeau requires_review, warnings catégorisés, force probante dossier
- DP/DAS : code suggestion barré → code final si modifié, ligne grisée si ruled_out, badges décision + règles
- DAS : badge needs_info avec détails, raison ruled_out sous la ligne
- VetoReport : section contestabilité avec verdict, barre score/100, tableau issues HARD/MEDIUM/LOW
- Biologie : badge Suspect avec tooltip, valeurs écartées en details pliable
- Nouveau filtre Jinja2 decision_badge, import _assess_dossier_strength (pas de duplication)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Les deux appels tronquaient systématiquement (done_reason=length),
causant des JSON invalides et des faux positifs adversariaux.
num_predict n'a aucun impact sur VRAM ni sur les réponses courtes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Score 0-10 basé sur les preuves objectives (bio/img/trt/actes).
Dossier faible (score < 3) : prompt LLM adapté + seuil adversarial
abaissé (score 2-3 → Tier B au lieu de C). Les éléments contextuels
(âge, IMC, urgence) restent dans le prompt mais hors du scoring car
ils ne constituent pas des preuves opposables à un contrôleur CPAM.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Le LLM (deepseek) propose systématiquement des codes alternatifs (D62,
T81.0, T80, R39.2) malgré l'interdiction dans le prompt. Ces codes
déclenchaient des warnings CRITIQUE → Tier C automatique.
Solution conforme au principe "LLM propose, moteur de règles dispose" :
- _sanitize_unauthorized_codes() supprime les codes hors whitelist du
texte de la réponse AVANT toute validation
- Nettoyage propre : "D62 — libellé" → "libellé", "(D62)" → ""
- _build_whitelist_prefixes() factorisé en helper partagé
- Sanitisation appliquée après génération ET après correction
- 9 tests unitaires couvrant tous les cas (parenthèses, tirets, multiple)
Résultat live : 0 warning CRITIQUE "code hors périmètre" sur 3 dossiers
(vs 6 warnings CRITIQUE avant). Le seul CRITIQUE restant est le score
adversarial bas, qui reflète des limites de raisonnement du modèle.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Argumentation + correction : max_tokens porté à 16000 (num_predict)
- ollama_client : log done_reason=length pour détecter les troncatures serveur
- Résultat live : 1/3 Tier B (dossier 132 passé de C à B, score 5/10)
- Les 2 Tier C restants sont bloqués par hallucination de codes et
absence de données bio, pas par max_tokens
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cause racine du Tier C : le LLM inventait des tags ([C83.3], [Antécédents])
car _build_tagged_context() ne taguait que bio/img/trt/actes. Le DP, les DAS,
antécédents et complications n'avaient aucun tag citable.
- cpam_context: 4 nouveaux types de tags [DP], [DAS-N], [ANT-N], [COMPL-N]
- cpam_validation: fuzzy matching — résout les refs CIM-10 nues vers le tag contenant ce code
- templates: liste explicite des tags valides, interdiction d'inventer des tags
- tests: 18 nouveaux tests (tags, fuzzy match, grounding DAS/DP)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- parse_json_response : réparation JSON tronqué par max_tokens (fermeture
auto des structures ouvertes), meilleur stripping des blocs fencés avec
texte superflu après la fermeture ```
- call_ollama : retry avec backoff exponentiel (1s/2s/4s) pour les erreurs
429 rate limit, 3 tentatives au lieu de 2
- Validation adversariale : max_tokens 800 → 1500
- Prompt CPAM : whitelist PÉRIMÈTRE DE CODES AUTORISÉS (dossier DP+DAS +
UCR) avec interdiction explicite des codes hors périmètre
- Tests : 19 tests parse_json/_repair_truncated_json, 6 tests whitelist
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Découpe le monolithe cpam_response.py (1207L) en 3 modules spécialisés :
- cpam_rag.py : recherche RAG ciblée (5 requêtes, dédup)
- cpam_context.py : construction prompt, définitions CIM-10, bio summary
- cpam_validation.py : grounding, références, codes fermée, adversariale
Le cpam_response.py reste orchestrateur (~230L) avec re-exports
backward-compat. Mocks des tests mis à jour pour cibler les bons modules.
Ajout RULE-CPAM-CORRECTION-LOOP dans base.yaml. 748 tests passent.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Ajout R33, R33.0, R33.8, R33.9, F17.1, F17.2 au dictionnaire supplémentaire
- Rejet des codes CIM-10 avec raisonnement ET justification vides (corrélation hallucinations)
- Validation du code contre le dictionnaire CIM-10 avant copie suggestion → final
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remplace onclick inline par data-excerpt/data-page + event delegation
(élimine les problèmes d'échappement JS dans attributs HTML)
- Nettoie les "..." préfixe/suffixe des extraits avant recherche
- Fallback morceau central si l'extrait complet ne matche pas
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ajoute source_page/source_excerpt à tous les types (biologie, imagerie,
traitements, actes CCAM, antécédents, complications). Convertit antecedents
et complications en types structurés (Antecedent/Complication) avec
validators backward-compat pour les vieux JSON. Étend _apply_source_tracking
à tous les éléments du dossier. Ajoute un endpoint /api/source-text/ et un
modal interactif dans le viewer avec surlignage du texte source.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- das_filter: regex anti-répétition gère les espaces entre mots concaténés
("VentilationVentilation Ventilation..." désormais rejeté)
- cim10_extractor: regex antécédents s'arrête à "Signes Vitaux" (ne capture
plus le tableau de surveillance)
- Nouveau _is_valid_antecedent() filtre noms de service, mots de surveillance
isolés, infos admin (RPPS), répétitions, Mode de vie
- 28 nouveaux tests (TestIsValidAntecedent + das_filter repetition)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Le 27b-cloud via Ollama Cloud est plus rapide (2m25 vs 4m) et
produit des résultats nettement supérieurs au 12b local :
- CPAM : plus de confusion Z45.80/Z43.6, preuves non hallucinées
- Contre-argumentation : 5334 chars vs 4394, citations du dossier
- Fallback local possible via OLLAMA_MODEL=gemma3:12b
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Ajout threading.Lock sur _get_embed_model() pour empêcher les
chargements concurrents depuis ThreadPool(2) — élimine les erreurs
"meta tensor" et les doubles CUDA OOM
- Sentinelle _embed_failed évite les retries infinis après échec
- NotImplementedError ajouté aux exceptions capturées (meta tensor)
- Fallback CPU protégé par try/except avec _embed_failed
- QC: alertes_globales string wrappée en liste (évite itération par
caractère quand le LLM retourne une string au lieu d'une liste)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
low_cpu_mem_usage=False évite les meta tensors lors du chargement
de l'embedding (sentence-transformers 5.x + accelerate 1.12).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Prompt : consigne de toujours citer les codes CIM-10 avec libellé (jamais
"codage initial" sans préciser le code), appliquée dans conclusion et partout
- RAG résilient : _search_rag_for_control attrape toute exception (meta tensor,
CUDA OOM, index absent) et génère la contre-argumentation sans sources plutôt
que de perdre silencieusement tout le contrôle CPAM
- Embedding fallback : condition élargie pour couvrir "meta tensor" en plus de
"memory" dans le message d'erreur RuntimeError
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>