diff --git a/docs/superpowers/plans/2026-06-25-gui-v6-beta-plan-1b-gating-coeur.md b/docs/superpowers/plans/2026-06-25-gui-v6-beta-plan-1b-gating-coeur.md index de4b524..d28d620 100644 --- a/docs/superpowers/plans/2026-06-25-gui-v6-beta-plan-1b-gating-coeur.md +++ b/docs/superpowers/plans/2026-06-25-gui-v6-beta-plan-1b-gating-coeur.md @@ -12,7 +12,7 @@ - VLM : `VLM_CATEGORY_MAP` (vlm_manager.py:51) `label→(kind, placeholder)` — source de vérité (Qwen ratait `VLM_CP`). - `_GLOBAL` : `PiiHit(kind=f"{kind}_GLOBAL")` (core:5286) pour `_CRITICAL_PII_TYPES` (core:5245) — **plusieurs** kinds, pas seulement NIR/ADHERENT. - Burn : `_VECTOR/_RASTER_SKIP_KINDS` (core:4564/4723) excluent déjà `EDS_SECU/EDS_TEL/EDS_DATE_NAISSANCE` du PDF. -- **Décision CP/ZIP** : code postal (`VLM_CP`, `EDS_ZIP`, placeholder `CODE_POSTAL`) = **PAS** dans les 7 toggles → **toujours masqué** (conservateur ; « Adresses » révèle la voie, pas le CP). À confirmer Dom. +- **Décision CP/ZIP** : code postal (`VLM_CP`, `EDS_ZIP`, placeholder `CODE_POSTAL`) = **PAS** dans les 7 toggles → **toujours masqué** (conservateur ; « Adresses » révèle la voie, pas le CP). Qwen d'accord (RGPD : le CP identifie le lieu de soin/résidence). **Caveat UX à documenter** : décocher « Adresses » donne un rendu type « 12 rue X [CODE_POSTAL] Ville » (voie en clair, CP masqué) — assumé. À confirmer Dom. **Référence spec :** `docs/superpowers/specs/2026-06-25-gui-v6-beta-prod-design.md` (chantier D, P1-2, D2/D3 : pas de plancher dur ; `EMAIL/IBAN/IPP/VILLE/FAX/CODE_POSTAL` non toggleables = toujours masqués). @@ -78,7 +78,7 @@ def test_filter_audit_drops_only_disabled(): - [ ] **Step 2 — Run, expect FAIL.** -- [ ] **Step 3 — Implement** (after `PLACEHOLDERS`/`CRITICAL_PII_KEYS` ~l.610). Lire `vlm_manager.VLM_CATEGORY_MAP` et `eds_pseudo_manager.EDS_LABEL_MAP` au moment de l'implémentation pour confirmer les noms ; importer ces deux modules en tête du core (imports déjà présents pour VLM ? sinon import paresseux dans le helper). +- [ ] **Step 3 — Implement** (after `PLACEHOLDERS`/`CRITICAL_PII_KEYS` ~l.610). Lire `vlm_manager.VLM_CATEGORY_MAP` et `eds_pseudo_manager.EDS_LABEL_MAP` au moment de l'implémentation pour confirmer les noms ; importer ces deux modules en tête du core (imports déjà présents pour VLM ? sinon import paresseux dans le helper). **Convention admin_rules (vérifiée Qwen — documenter, pas de branche supplémentaire)** : `_apply_admin_identifier_hits` (~l.1376) émet des kinds = **clés de `PLACEHOLDERS`** (ex. "NOM", "NIR", "TEL") → captés par la branche 3 (placeholder-self). Un admin_rule à kind custom hors `PLACEHOLDERS` → `None` → toujours masqué (conservateur, sûr). ```python # 7 catégories toggleables ↔ type de placeholder. Tout autre placeholder → None (masqué). @@ -149,7 +149,7 @@ Add `disabled_kinds: set = None` kwarg to `process_pdf` (~l.4973). After `cfg = - [ ] **Step 1 — Failing test.** Refactor inline patterns into `_build_residual_patterns(disabled_kinds)` and test : labels include {NIR,EMAIL,IBAN,TEL} when none disabled ; NIR absent when `{"NIR"}` (EMAIL/IBAN restent) ; TEL absent when `{"TEL"}` ; **et** quand NIR disabled, le pattern TEL ne matche PAS un NIR en clair (test : `_build_residual_patterns({"NIR"})` appliqué à « 1 85 05 74 123 456 78 » → 0 match). - [ ] **Step 2 — Run, expect FAIL.** -- [ ] **Step 3 — Implement.** `_build_residual_patterns(disabled)` : EMAIL+IBAN toujours ; NIR si `"NIR" not in disabled` ; TEL si `"TEL" not in disabled` ; **quand NIR disabled, le pattern TEL doit exclure les spans de type NIR** (13-15 chiffres groupés) — soit en pré-masquant les spans NIR-like, soit en bornant le pattern TEL. Gate la branche INSEE-names (~l.5470) sous `"NOM" not in disabled`. Brancher `cfg.get("disabled_kinds")`. +- [ ] **Step 3 — Implement.** `_build_residual_patterns(disabled)` : EMAIL+IBAN toujours ; NIR si `"NIR" not in disabled` ; TEL si `"TEL" not in disabled` ; **quand NIR disabled, le pattern TEL doit exclure les spans de type NIR** (13-15 chiffres groupés) — soit en pré-masquant les spans NIR-like, soit en bornant le pattern TEL. Gate la branche INSEE-names (~l.5470) sous `"NOM" not in disabled`. Brancher `cfg.get("disabled_kinds")`. **Seuil adaptatif (suggestion re-revue Qwen)** : `SEUIL_RESCAN_RESIDUEL=0` est trop strict quand des catégories sont décochées (un fragment de 8 chiffres peut matcher le pattern TEL résiduel → quarantaine injustifiée) ; passer le seuil à **1 si `disabled_kinds` non vide**, 0 sinon (préserve la rigueur quand tout est activé). - [ ] **Step 4 — Run, expect PASS.** - [ ] **Step 5 — Non-régression :** `.venv/bin/pytest tests/unit/ -q`. - [ ] **Step 6 — Commit :** `git commit -m "feat(core): coordination quarantaine résiduelle NIR/TEL décochés (P1-2/F-4)"` @@ -165,7 +165,7 @@ Add `disabled_kinds: set = None` kwarg to `process_pdf` (~l.4973). After `cfg = - KV distincts (F-2) : `_mask_structured_line` (~2042→ADHERENT/NOM), `_mask_critical_in_key` (~2004→TEL/ADRESSE), `_apply_admin_identifier_hits` (~1376→dynamique : OK via default-deny si kind mappable). - Noms : `_apply_extracted_names` (~2809→early-return si NOM off). - **NER — INTRA-BOUCLE par placeholder (F-5, point le plus fragile)** : `_mask_with_hf` (~3136) et `_mask_with_eds_pseudo` (~3208) — **NE PAS** sauter la fonction entière (perdrait ETAB/VILLE) ; sauter **par hit** selon `_category_of(kind)`/placeholder. -- Trackare (F-2) : `_apply_trackare_hits_to_text` (~2909→NIR/DOSSIER) — gate NIR. +- Trackare (F-2) : `_apply_trackare_hits_to_text` (~2909→NIR/DOSSIER) — gate NIR ; **`RE_TRACKARE_IAO_MULTILINE_VALUE` (~3102→NOM_FORCE) — gate NOM** (site ajouté re-revue Qwen ; sinon NOM faussé sur docs Trackare IAO). - selective_rescan (~4159) : DATE_NAISSANCE(4203), ADRESSE(4205-4207), ETAB(4229-4251), ADHERENT(4200-4201), TEL(4191-4193), NIR(4187-4188). - Phase-0 multiline : DATE_NAISSANCE(~3014), NIR(~3034). - **Propagation globale step 4e (F-2 #1, F-4)** : boucle `_CRITICAL_PII_TYPES`/`{kind}_GLOBAL` (~5279-5286) — ne pas propager une catégorie désactivée.