From 217fc75983b5375ba386c979a0e2990d4f76d645 Mon Sep 17 00:00:00 2001 From: Domi31tls Date: Fri, 29 May 2026 21:39:47 +0200 Subject: [PATCH] feat(q1): E - B-3 preflight text too short, quarantine direct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Étape E du sprint Q-1 — B-3 pré-flight. Si extract_text_with_fallback_ocr retourne moins de SEUIL_TEXTE_MINI (=100) caractères : - log.warning systématique - Si quarantine_mgr fourni : flag preflight_text_too_short (severity=full), copie du PDF original dans quarantine_dir/ pour ré-essai manuel - Return {} (pas de sortie texte/audit/PDF pour ce doc) Couvre les cas : scan non-OCRisé, PDF vide, OCR raté. Évite le pire scénario : un opérateur qui croit que son document est anonymisé alors qu'aucune PII n'a même été détectée parce qu'il n'y avait pas de texte à traiter. Rétro-compat préservée : sans quarantine_mgr, le comportement reste "return {}" + log au lieu du silence (toujours strictement meilleur). Risque appelants : un caller qui suppose la présence des clés "text"/ "audit" dans le retour doit gérer le cas dict vide. À voir au runtime. Ref: docs/coordination/inbox/for-dom/2026-05-29_consolide_pseudocode-Q1-v2.md §8 Co-Authored-By: Claude Opus 4.7 (1M context) --- anonymizer_core_refactored_onnx.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/anonymizer_core_refactored_onnx.py b/anonymizer_core_refactored_onnx.py index 1b851b8..171c7c1 100644 --- a/anonymizer_core_refactored_onnx.py +++ b/anonymizer_core_refactored_onnx.py @@ -4279,6 +4279,30 @@ def process_pdf( cfg = load_dictionaries(config_path) pages_text, tables_lines, ocr_used, ocr_word_map = extract_text_with_fallback_ocr(pdf_path) + # Q-1 B-3 : pré-flight texte vide. Si moins de SEUIL_TEXTE_MINI caractères + # extraits, c'est probablement un scan non-OCRisé ou un document corrompu. + # On NE traite PAS — quarantaine totale, le doc original est copié pour + # ré-essai manuel. + extracted_chars = sum(len(p) for p in pages_text) + if extracted_chars < SEUIL_TEXTE_MINI: + log.warning("Preflight failed for %s: only %d chars extracted (seuil=%d)", + pdf_path.name, extracted_chars, SEUIL_TEXTE_MINI) + if quarantine_mgr is not None: + quarantine_mgr.flag( + doc_name=pdf_path.stem, + reason="preflight_text_too_short", + detail=f"Only {extracted_chars} chars extracted from {len(pages_text)} pages (seuil={SEUIL_TEXTE_MINI})", + severity="full", + extracted_chars=extracted_chars, + ) + try: + quarantine_mgr.quarantine_dir.mkdir(parents=True, exist_ok=True) + shutil.copy(pdf_path, quarantine_mgr.quarantine_dir / pdf_path.name) + except Exception as copy_err: + log.warning("Could not copy original PDF to quarantine for %s: %s", + pdf_path.name, copy_err) + return {} + # 1) Regex rules + NER-first cross-validation # Passer les NER managers pour que anonymise_document_regex exécute le NER # sur le texte original (non masqué) et valide les noms extraits par regex