Commit Graph

60 Commits

Author SHA1 Message Date
416b347d7f feat(gui): confirmation explicite avant anonymisation regex-only (NER off)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 19:07:38 +02:00
880a75873d feat(gui): charger le dictionnaires.yml externe éditable en frozen (P1-4)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 19:00:49 +02:00
4357a58d7d fix(core): exempter les hits forcés (overrides) du filtre catégorie — anti-fuite PDF (P1-2/T1)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:38:19 +02:00
bf832e12f0 feat(gui): câbler les 7 toggles catégories au moteur (P1-2)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 11:33:13 +02:00
daec1f53bd feat(core): garde-fou adresse burn + doc chemins conservateurs (P1-2/F-3)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 11:13:42 +02:00
a02bca516d feat(core): gates texte par catégorie sur toutes les passes (P1-2/F-2/F-5)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 11:03:04 +02:00
2a3aab117d feat(core): coordination quarantaine résiduelle NIR/TEL décochés (P1-2/F-4)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 10:21:27 +02:00
b15d0da141 feat(core): _category_of dérivé (anti-dérive) + filtre audit Tier 1 (P1-2/F-1)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 10:04:03 +02:00
2aa5a43261 harden(gui): centraliser fail-close repli + garde-fou logging + doc mutex (revue finale Plan 1a)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 18:09:52 +02:00
6476fe9f98 feat(gui): instance unique + mutex partagé installeur (P0-7)
Protection multi-instance GUI V6 : mutex kernel nommé sur Windows (partagé
avec l'installeur Inno via AppMutex), fcntl exclusif sur POSIX (dev/test).
3 tests unitaires, self-test OK, 0 régression gui_v6 (145 passed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 18:01:28 +02:00
d4891f5cfd fix(gui): flag legacy ONNX + log fichier dès l'entrée frozen (P0-5/E1)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 17:58:05 +02:00
9296c28bed feat(gui): log fichier rotatif V6 à chemin connu (E1) 2026-06-25 17:56:50 +02:00
9e87cb3122 feat(gui): binding licence-poste souple (P0-6/D-20.4, affichage sans blocage) 2026-06-25 17:52:07 +02:00
dc0554e694 fix(gui): fail-close si CamemBERT-bio indisponible (P0-1, anti-fuite PII)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 17:46:50 +02:00
f3e6cdb980 fix(gui): connecter la GUI V6 au portail prod (P0-2, plus localhost)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 17:40:33 +02:00
8d683bc6d8 feat(ocr): migrer l'OCR de docTR (PyTorch) vers OnnxTR (ONNX Runtime)
OnnxTR exécute les MÊMES modèles que docTR (db_resnet50 + crnn_vgg16_bn) sur
ONNX Runtime, sans PyTorch. Corrige le crash torch/oneDNN « could not create a
primitive » sur CPU contraint (VM 2 cœurs collaborateur : OCR scan impossible →
quarantaine). Qualité identique validée empiriquement (CER 0,10-0,23 % vs docTR,
2 validations indépendantes Claude+Qwen), OCR ~2-3× plus rapide CPU.

- core : import OnnxTR, _get_ocr_model(), _OCR_AVAILABLE, boucle OCR inchangée
  (API miroir) ; ONNXTR_CACHE_DIR pour le frozen ; bandeau de logs ENV au démarrage
  (OS, CPU+AVX, cœurs, RAM, versions, providers) pour retours terrain auto-suffisants.
- 3 .spec : embarquent les poids ONNX OnnxTR (fail-closed) + hiddenimports onnxtr.
- requirements : onnxtr[cpu] (python-doctr conservé transitoirement).
- inclut le correctif quarantaine-visible du runner (GO Qwen).

Tests : test_ocr_onnxtr.py (RED→GREEN), 95 unit passed, e2e scan client OK
(OCR 5/5, PDF produit, plus de crash). Retrait torch du frozen + rebuild Windows
= étapes suivantes (gates Dom).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 17:07:00 +02:00
19c4934de3 fix(gui): rendre les profils lisibles sous windows 2026-06-17 23:01:27 +02:00
ea1752d4a7 feat(cli): charger les moteurs optionnels depuis les modeles embarques 2026-06-17 19:52:29 +02:00
9b40fc0a85 fix(gui): rendre les profils scrollables a la molette
Ajoute un conteneur scrollable dedie au sous-onglet Profils pour permettre le defilement souris du formulaire complet. Tests GUI: test_gui_v6_profiles.py et test_gui_v6_*.py.
2026-06-17 18:05:45 +02:00
dc0616f744 fix(ner): convertir les entrees ONNX en int64
Force input_ids et attention_mask en int64 avant inference CamemBERT ONNX, pour eviter les erreurs de dtype selon les tokenizers/environnements Windows. Test cible: test_camembert_manager_cache.py.
2026-06-17 18:01:57 +02:00
60fb41c2e7 fix(gui): clarifier aide et disponibilite moteurs
Passe theme clair, libelles utilisateur, aides conteneurs, recherche de mise a jour et indication honnete des moteurs optionnels non embarques. Tests GUI unitaires: 126 passed.
2026-06-17 18:01:25 +02:00
d18ca919fa fix(core): renforcer detection PII et FINESS Corse
Couvre les corrections PII batch A/A-2, le NIR multi-ligne en flux reel, le gazetteer FINESS Corse derive depuis la base locale, et les tests de regression associes. Aucun build ni diffusion.
2026-06-17 17:59:27 +02:00
536ab81184 feat(gui): garde-fou runtime — désactive un moteur optionnel non embarqué
Condition du GO-CONDITIONNEL Qwen sur le lot engine capabilities
(cb3b767/890edb3/5e5f0bd) : un profil YAML forçant enable_eds/enable_gliner
ne doit pas déclencher un chargement voué à l'échec silencieux.

NerManagers.ensure_loaded() applique désormais un garde-fou via la sonde
engine_capabilities.capabilities_map() (injectable) AVANT toute tentative
de load EDS/GLiNER : si le moteur optionnel demandé est indisponible dans
le build courant → warning + désactivation forcée dans les réglages runtime.
Best-effort (sonde en échec ⇒ réglages inchangés, les try/except de load
protègent déjà). Sonde légère (find_spec), aucun import lourd.

CamemBERT (requis) inchangé. Diff limité au garde-fou + tests cibles.

TDD : 4 tests (test_gui_v6_engine_bridge.py) — eds/gliner indispo désactivés
et jamais chargés, moteur dispo conservé, fail-safe sonde. 282 unit passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 11:56:47 +02:00
5e5f0bd341 feat(gui): n'afficher comme disponibles que les moteurs embarqués dans le build GUI
Axe application GUI (utilisateur final) : cohérence UI/moteurs propre au build
GUI, sans présumer du build CLI. EDS-Pseudo / GLiNER désactivés (switch disabled
+ « non embarqué dans cette version ») et `enable_eds/gliner` forcés à False quand
indisponibles ; CamemBERT-bio reste le moteur standard actif. Note Moteurs des
Profils rendue honnête. `_mini_toggle` gère `disabled`/`disabled_hint` + `.switch`.

2 tests GUI (toggles désactivés si indispo + état forcé False ; actifs si dispo).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 17:38:56 +02:00
890edb360e feat(cli): option --engines, diagnostic honnête des moteurs du build CLI
Axe CLI (intégration dans d'autres programmes) : contrat stable, codes retour
fiables. `--engines` liste les moteurs réellement disponibles dans CET
exécutable CLI (`[OUI]/[NON] Label (requis/optionnel) — raison`) et sort 0, sans
traiter. `input` devient optionnel pour ce mode (sinon code 2).

Le fail-closed CamemBERT (code 3) et le best-effort EDS/GLiNER (jamais déclarés
actifs si le chargement échoue) restent inchangés. Ne présume pas du build GUI.

2 tests (--engines → code 0 + moteurs listés ; absence d'input → code 2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 17:38:56 +02:00
cb3b7675bb feat(engines): fondation 'capabilities moteurs' testable et partagée
Utilitaire neutre (ni CLI ni GUI) qui dit la vérité sur les moteurs réellement
disponibles dans le build COURANT (la sonde reflète l'exécutable qui tourne, sans
présumer d'un autre build). Consommé séparément par chaque axe produit.

- `EngineCapability(key, label, available, required, reason)`.
- Sondes légères `importlib.util.find_spec` (pas d'import lourd au démarrage) +
  présence du modèle ONNX pour CamemBERT (gère _MEIPASS en frozen).
- camembert=requis ; eds (edsnlp+spacy) / gliner=optionnels. Sondes injectables,
  fail-closed. `capabilities_map()` / `available_engines()`.

6 tests (sondes injectables dispo/indispo, required, reasons, sondes réelles).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 17:38:56 +02:00
764cf00581 refactor(gui): intégrer les Règles dans Administration > Profils
Retour Dom : « les règles du profil doivent être dans le menu profil, pas à
part ! ». Même logique que le Masquage — les règles qui influencent
l'anonymisation appartiennent au profil ; un sous-onglet séparé crée la
même confusion.

- Retrait du sous-onglet « Administration > Règles » (_SUBTABS, builder,
  méthode _build_regles supprimée). Sous-onglets restants : Réglages /
  Profils / Partage.
- Section « Profils > Règles du profil » enrichie : wording clair (règles
  d'anonymisation portées par le profil), aperçu illustratif de la table
  des règles (réutilise _rule_row + _HELP_REGLES), édition fine annoncée
  « à venir ».
- Abandon du « Testeur de règle » (écran outil global) pour ne pas
  réintroduire un second réglage métier.

Cible UX : Réglages / Profils (Général・Masquage・Mots・Moteurs・Règles du
profil) / Partage. Test obsolète test_rules_subtab_has_no_unexplained_2
remplacé par test_no_separate_rules_subtab.

262 tests unit OK (0 régression), self-test OK, nav 3 sous-onglets + section
Règles dans Profils + thème OK. Préserve d8bc0cd + GO Qwen. Aucun build/push
sans GO Dom.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 12:00:10 +02:00
d8bc0cd8c8 refactor(gui): intégrer le Masquage dans Administration > Profils
Retour Dom : le sous-onglet Masquage séparé créait de la confusion. Le
masquage fait partie de la manière d'anonymiser associée au profil.

- Retrait du sous-onglet « Administration > Masquage » (_SUBTABS, builder,
  méthode _build_masquage).
- Section « Profils > Masquage » enrichie : masque manuel requis, template
  de masque (lié au profil édité), bouton « Ouvrir l'éditeur de masque »
  (fenêtre dédiée) + dossier des templates, et apparence du masque
  (couleur, style des marqueurs + aperçu, marges H/V, coins arrondis).
- Le template enregistré depuis l'éditeur remplit désormais le champ
  Template du profil (preferred_manual_mask_template via _pro_template_var).
- Profils devient le centre des réglages métier (général/masquage/mots/
  moteurs/règles). Réglages inchangé (pas de pastilles, pas de grosse
  refonte). Nettoyage du code mort (_REPLACEMENT_CODES, _HELP_MASQUAGE).

261 tests unit OK (0 régression), self-test OK, nav 4 sous-onglets + éditeur
de masque depuis Profils + thème OK. Préserve 72841ed/GO Qwen. Aucun build/
push sans GO Dom.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 10:24:49 +02:00
72841ed7b3 feat(gui): onglet Profils éditable (création/modification/persistance)
Retour Dom : remplacer la page vitrine par un vrai éditeur de profils.

- gui_v6/profile_editor.py : couche logique (build_profile_spec,
  profile_is_editable runtime vs defaut, list_profile_choices, slug_for_copy,
  save/set_default/delete) au-dessus de profile_defaults — persistance dans
  config/profiles.yml.
- gui_v6/editable_list.py : EditableTermList (tableau scrollable de termes,
  ajout/suppression, pas de pastilles) — reste lisible à 50+ termes.
- tab_config : sous-onglet « 👤 Profils » réintroduit comme éditeur — menu
  déroulant « Profil à modifier », boutons Nouveau / Dupliquer / Enregistrer /
  Annuler / Définir par défaut, sections Identité, Masquage (require_manual_mask,
  template), Moteurs (force_disable_vlm), Mots (à masquer/conserver/ignorer
  éditables), Règles « à venir ». Profils défaut = lecture seule (dupliquer
  pour modifier). Confirmation non bloquante (pas de modale).
- Réglages : bouton « ✏️ Modifier le profil… » → ouvre Profils sur le profil
  actif. Pas de pastilles inline.

Persiste : label, description, require_manual_mask, force_disable_vlm,
preferred_manual_mask_template, param_lists (3 listes). 260 tests unit OK
(0 régression), self-test OK, nav 5 sous-onglets + thème OK. Préserve
1bbe70a/d30f7b7. Aucun build/push sans GO Dom.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 23:09:01 +02:00
1bbe70a911 feat(gui): câbler l'envoi de la télémétrie d'usage en fin de run
Le module usage_telemetry est maintenant réellement branché : la GUI V6
envoie les statistiques au portail après chaque run (les stats web
restaient vides sans cela).

- processing_runner : RunSummary porte une liste DocResult (ordinal,
  page_count via page_count_for, status, duration_ms, extension) — peuplée
  dans la boucle. Aucun nom/chemin de fichier.
- usage_telemetry : report_run_summary(summary, base_url, license_ref,
  machine_id, session, ...) construit le payload depuis le RunSummary et
  l'envoie (non bloquant). N'envoie RIEN sans license_ref. Spool JSONL si
  échec réseau.
- tab_usage : _finish() déclenche l'envoi en thread daemon (jamais bloquant
  pour l'UI ni le run).
- app : fournit le reporter à UsageTab avec le contexte licence (base_url du
  LicenseClient, license_ref via local_status, machine_id, app_version).

Tests : RunSummary.documents peuplé (0 chemin) ; report_run_summary (payload
correct, réseau KO → spool sans crash, pas d'envoi sans licence) ; _finish
appelle le reporter. 252 tests unit OK (0 régression), self-test OK.
V5/moteur/app_aivanov intacts, 0 dépendance. Aucun build/push sans GO Dom.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 21:24:43 +02:00
d30f7b74ef refactor(gui): Réglages — tableau des termes en accès direct, retrait du doublon Profils
Retour Dom après validation visuelle : simplifier.

- Réglages > Listes locales : suppression des pastilles de termes et des
  éditeurs inline (_compact_tag_editor). Remplacés par un texte court +
  compteurs (À conserver/À masquer/À ignorer du profil actif) + bouton
  « Ouvrir le tableau des termes » qui ouvre DIRECTEMENT TermsTableWindow.
- Retrait du bouton « Voir le profil » (son rôle = accéder au tableau).
- Retrait du sous-onglet « Profils » (doublon non câblé) : _SUBTABS,
  builders, _build_profils/_rebuild_profils. Les helpers profil
  (_active_profile_summary/_open_terms_table) sont conservés pour Réglages.
- Nettoyage du code mort associé : _compact_tag_editor, constantes
  _PRESERVE_TERMS/_MASK_TERMS/_STOPWORDS, textes d'aide qui référençaient
  l'onglet Profils.

Chemin utilisateur : Administration > Réglages > Ouvrir le tableau des
termes. 247 tests unit OK (0 régression), self-test OK. Préserve a9e8b2c
(thème, bêta, aide ?, fenêtre tableau). Aucun build/push sans GO Dom.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 17:45:43 +02:00
ab2ca8a552 feat(gui): module télémétrie d'usage (client, RGPD-safe, non bloquant)
Phase A de la mission télémétrie d'usage par client.

- gui_v6/usage_telemetry.py :
  - page_count_for(path) : PDF→fitz, image→1, autres→None ; best-effort, ne
    lève jamais, ne lit que l'extension (jamais le nom).
  - build_usage_payload(...) : compteurs (document/succeeded/failed/total_pages)
    + documents filtrés aux seules clés autorisées (ordinal/page_count/status/
    duration_ms/extension) → aucun nom/chemin de fichier ne peut fuir.
  - UsageTelemetryClient(session injectée) : report() non bloquant (capture
    tout, False en cas d'échec réseau) vers POST /api/v1/usage/report.
  - spool JSONL local (spool_payload/flush_spool) pour rejouer les échecs.

Module isolé, non câblé au runner pour l'instant (le branchement fin-de-run
viendra après le backend, hors validation visuelle GUI en cours). Aucun
build/push sans GO Dom. 10 tests unitaires (payload sans nom de fichier,
réseau indispo ne crashe pas, compteurs, page_count PDF mockable).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 17:13:57 +02:00
a9e8b2c2e6 feat(gui): addenda Dom GUI V6 — sous-onglet Profils, libellés, aide, bêta
Suite des retours Dom sur la GUI V6 (par-dessus 6a0a581).

Addendum Profils / Réglages :
- Nouveau sous-onglet Administration « 👤 Profils » : le profil actif devient
  un objet lisible (nom, description, masque requis, template, listes locales
  avec compteurs) — données réelles lues depuis profile_defaults.
- Fenêtre « Tableau des termes » (terms_table_window.py) : table scrollable
  avec recherche/filtre, colonnes Type/Terme/Source ; reste lisible à 50+
  termes. Ajouter/éditer/supprimer désactivés « (à venir) » (écriture par
  profil non câblée).
- Réglages : « Profil métier » → « Profil d'anonymisation », « Sortie… » →
  « Dossier de sortie… » (+ infobulle), hints moteurs (standard/optionnel/
  plus lent), bouton « Voir le profil », « Ouvrir le tableau des termes ».
- Aide « ? » + infobulles (ui_kit.attach_tooltip) près des éléments ambigus.
- profile_view.py : logique pure (résumé profil + lignes du tableau),
  testable sans display.

Addendum bêta : en-tête « aivanonym » + badge « bêta », titre fenêtre
« … — bêta ». Détail version conservé dans À propos.

tests/unit/test_gui_v6_profiles.py + ajouts shell. 237 tests unit OK
(228 → 237, 0 régression), self-test GUI V6 OK, navigation des 5 sous-onglets
+ thème OK. V5/moteur/app_aivanov/profile_defaults non touchés, 0 dépendance.
Aucun build/push sans GO Dom — validation visuelle Dom attendue.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 17:02:54 +02:00
6a0a5811a5 fix(gui): retours Dom GUI V6 — thème, Administration, Règles, aide
Cinq retours utilisateur sur l'exécutable Windows GUI V6.

- Thème : `_render()` vidait les widgets mais conservait le cache
  `_tab_frames`/`_visible_tab` → l'onglet Utilisation se vidait (TclError
  sur widget détruit) au changement de thème. Reset du cache dans
  `_render()` → onglet actif recréé proprement.
- Onglet principal « Configuration » → « Administration » (clé interne
  inchangée).
- Sous-onglet « Règles  2 » → « Règles » (le « 2 » était un badge non
  câblé).
- Actions de maquette non câblées (Partage Export/Import, Règles Nouvelle
  règle/Recharger/Tester/Fermer) désactivées + suffixe « (à venir) » via
  `_mockup_button` : plus aucune action morte qui semble fonctionner.
- Aide « ? » restaurée (façon V5) : `ui_kit.HelpButton`/`help_button`
  réutilisable ouvrant une fenêtre d'aide en français simple, posée sur
  Utilisation, Administration (Réglages/Masquage/Partage/Règles) et
  À propos. Partage : phrase visible + aide expliquant qu'on partage les
  réglages, jamais les documents patients.

`tests/unit/test_gui_v6_app_shell.py` : régression thème, libellés,
présence d'aide, navigation. 228 tests unit OK (0 régression), self-test
GUI V6 OK. V5/moteur/app_aivanov non touchés, aucune dépendance ajoutée.
Verdict Qwen requis avant push/build/diffusion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 16:39:53 +02:00
13b79db417 feat(gui): éditeur de masques en fenêtre dédiée (GUI V6)
Remplace l'éditeur de masquage encastré dans l'onglet Configuration —
jugé inutilisable par Dom (document trop à l'étroit, non défilable) —
par une fenêtre dédiée où le document est majoritaire et réellement
navigable.

- gui_v6/mask_editor_model.py : couche logique pure (rectangles par
  page, conversions écran↔PDF, hit-test, sérialisation template)
  testable sans display ; réutilise MaskRect/Template de
  pdf_mask_designer → format de template inchangé (compat moteur).
- gui_v6/mask_editor_window.py : MaskEditorWindow (CTkToplevel)
  redimensionnable — canvas + scrollbars H+V câblées + molette (le
  manque qui rendait l'éditeur inutilisable), zoom + ajuster
  largeur/page, navigation pages, rectangles au glisser-déposer,
  sélection (clic) + suppression (Suppr / clic-droit), templates
  JSON/YAML, mode aperçu d'exemple sans PDF.
- tab_config.py : l'onglet Masquage lance la fenêtre dédiée ; retrait
  du canvas encastré et de ~290 lignes de code mort associé.
- tests/unit/test_gui_v6_mask_editor.py : 13 tests logique + 3 smoke
  headless (scrollbars, ajout/sélection/suppression, save/load
  roundtrip, câblage onglet→fenêtre).

Sans nouvelle dépendance. V5, moteur et app_aivanov non touchés.
221 tests unit OK (0 régression), self-test GUI V6 OK.
Verdict Qwen requis avant push/build/diffusion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:05:57 +02:00
696f6bf27c fix(gui): make admin config responsive and mask editor usable 2026-06-15 09:53:56 +02:00
269b9e0e13 fix(gui): complete V6 admin configuration mockup 2026-06-15 09:19:43 +02:00
fff4a2d902 fix(cli): avoid duplicate ONNX native load in Windows frozen 2026-06-12 16:49:11 +02:00
1bced55b81 feat(gui): GUI V6 G4 — alignement visuel sur la maquette v6 (option A)
Refonte de la couche présentation pour reprendre docs/ui_mockup_v6.html, sans
changer de techno UI ni la logique G1-G3.

- theme.py : 4 thèmes aux tokens EXACTS de la maquette (sombre #1a1a2e/#16213e/
  #e94560, clair, médical, neutre), palette complète + status_color.
- ui_kit.py (nouveau) : composants stylés (Card titrée, boutons primary/secondary/
  success/pilule, StatCard, ToggleRow) appliquant la palette.
- app.py : shell étroit, header identité + version + statut licence + liseré accent,
  barre d'onglets custom (plus de CTkTabview brut), navigation par recréation,
  changement de thème à chaud.
- tab_usage : carte Apparence (sélecteur de thème), dropzone stylée, grille formats,
  barre d'actions, progression à étapes + journal, résultats en cartes statistiques.
- tab_config : sous-navigation Réglages/Masquage/Partage/Règles ; Réglages câblé au
  ConfigState (profil, moteurs NER, dossier sortie).
- tab_about : grille d'informations + bloc licence (logique inchangée).

Logique inchangée : engine_bridge, config_state, license_client/store, runner.
Tests : +9 (theme). self-test exit 0, 55 tests gui_v6, 202 tests/unit (0 régression).
Smoke construction headless (Xvfb) : 3 onglets × 4 thèmes rendus sans erreur.
Pas de pywebview, aucun .exe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 12:06:05 +02:00
9575714ae2 feat(gui): GUI V6 G3 — câblage moteur, Configuration, licence UI, build-prep
G3-A câblage moteur réel (engine_bridge.py) : EngineSettings + NerManagers à
chargement paresseux (aucun manager à l'import), kwargs alignés CLI/V5
(make_vector_redaction=False, also_make_raster_burn=True, config_path, use_hf,
ner/gliner/camembert_manager, ogc_label) ; make_process_fn engine injectable ;
état managers not_loaded/loading/ready/unavailable, échecs optionnels tolérés.

G3-B Configuration (config_state.py + tabs/tab_config.py) : ConfigState →
EngineSettings, profils via profile_defaults (path injectable), options
raster/NER local/profil/sortie, état managers, sections admin-only via admin_mode.

G3-C Licence UI (machine_id.py + tab_about) : activation par clef
(LicenseClient.activate), bouton vérifier (check), affichage statut, aucun token
loggé, aucun appel réseau au démarrage (local_status seul).

Intégration : tab_usage exécute via le moteur réel selon ConfigState
(make_process_fn), anti double-lancement UI. app.py câble Config↔Usage↔licence.

G3-D build-prep : anonymisation_gui_v6_onefile.spec (entry V6, customtkinter +
modules gui_v6 en hiddenimports). Installateur Anonymisation.iss produit déjà la
cible Anonymisation-Setup.exe. Aucun artefact .exe commité ; build Windows à part.

Tests +14 (engine_bridge 8, config_state 6). self-test exit 0, 46 tests gui_v6,
193 tests/unit (0 régression). Moteur/V5/specs CLI intacts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 10:53:47 +02:00
9bc6537233 feat(gui): add GUI V6 G2 — onglet Utilisation + runner injectable
Onglet Utilisation fonctionnel (couche présentation only) :
- processing_runner: runner testable sans display/moteur lourd, process_fn
  injectable (défaut = process_document en import paresseux), découverte
  fichier/dossier, sorties anonymise/ comme V5 (arbo préservée), progression,
  journal, résumé OK/KO, arrêt coopératif entre documents, anti double-lancement
- tabs/tab_usage: sélection fichier/dossier + nb PDF détectés, dossier sortie
  (défaut anonymise/), Lancer/Arrêter, barre de progression, statut, journal,
  résumé ; worker threadé, file d'événements drainée par after() ; aucun réseau
- app.py: onglet Utilisation câblé (placeholder G2 retiré)
- self-test: couvre processing_runner + tab_usage

Tests: +11 (runner) — discovery, sorties, échec partiel, arrêt, anti-double-run,
callbacks. self-test exit 0, 32 tests gui_v6, 179 tests/unit (0 régression).
Moteur/V5/managers/specs intacts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 18:58:10 +02:00
a6ee68a8a3 feat(gui): add GUI V6 G1 foundation (license client/store, shell, About tab)
Socle de la refonte GUI V6 (couche présentation uniquement, aucune logique de
détection) :
- license_store: stockage licence hors dépôt (%LOCALAPPDATA%/Aivanov | XDG),
  read/write atomique/delete, ne journalise aucun token
- license_client: LicenseStatus + activate/check/local_status, session HTTP
  injectable, serveur indisponible géré sans crash, aucune clé privée
- theme: 4 thèmes + couleurs de statut licence
- app + tab_about: shell customtkinter minimal (header, bandeau licence,
  3 onglets), onglet À propos étoffé
- Pseudonymisation_Gui_V6.py: point d'entrée + --self-test (exit 0 sans fenêtre)
- requirements.txt: customtkinter==5.2.2

Tests: 20 nouveaux (store sur vrais fichiers, client sur session injectée).
Suite tests/unit: 167 passed, 0 régression. V5/moteur/managers/specs intacts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 18:50:23 +02:00
0e44cd4543 feat(anonymizer): add v11.5 P0 layout-aware detectors
Trois détecteurs simples « layout/context-aware » (chantier v11.5 P0),
validés par 2 revues Codex + 10 tests adversariaux Qwen, 0 régression :

- RE_ADRESSE réécrit en grammaire de tokens (_RE_VOIE_TYPE + _RE_VOIE_TOKEN) :
  capture initiales (« J. Loeb »), voies commémoratives à chiffres
  (« 8 Mai 1945 »), apostrophes ' et ’, bornage à la ligne courante,
  arrêt sur point post-mot (anti-débordement clinique).
- _mask_ville_gazetteers : retourne toujours un tuple (texte, liste) même
  sans Aho-Corasick ; masque les communes Saint/St/Sainte/Ste multi-mots à
  espaces (« St Martin de Hinx ») entièrement, sans exiger de contexte géo.
- DATE_NAISSANCE retiré de la propagation globale + DATE_NAISSANCE_GLOBAL
  ajouté aux skip vector/raster : on ne masque plus une date nue sur tout le
  document. La DDN reste masquée en contexte fort, page par page. Les dates
  cliniques identiques à la DDN hors contexte sont préservées.

tests/unit/test_p0_layout_detectors.py : 38 tests dédiés (matrice adresse
générique, anti-FP, communes Saint, propagation DDN, 10 tests adversariaux
Qwen). Suite tests/unit complète : 147 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 10:28:18 +02:00
c582c13a08 fix(anonymizer): cover CHCB real-world staff layouts 2026-06-08 12:44:09 +02:00
94f7903af3 fix(anonymizer): handle FC14 practitioner OGC rules 2026-06-08 12:03:51 +02:00
21a408a9e4 fix(perf): apply MVP threading hotfix
Configure numerical library and torch threading for H1, keep raster threading/timing instrumentation, remove CONCERTATION from forced masks after real PDF FP testing, and record coordination archive state.
2026-06-08 10:41:15 +02:00
f2375d6be2 test: non-régression F5 + batch paths + masquage manuel + layouts réels
- test_f5_nom_compose_orphelin.py : 13 tests (regex F5, application, scénario Trackare EJNAINI)
- test_gui_batch_paths.py / test_manual_masking.py : couverture des modules
- test_real_world_identifier_layouts.py : non-régression layouts réels (D-15)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 16:30:56 +02:00
65d6c8c603 test(T-G): réparer corpus synthétique post-cleanup CHCB + dégel 009
- Fixtures 001/003/004/005/010 : CHCB → CHUXX (D-12)
- 009 : Biarritz désormais masqué [VILLE] (bug connu résolu par F1-F4),
  retrait de KNOWN_FAILURES + restauration de Biarritz dans must_not_contain
- test_q1_quarantine.py : tests réels B-3/D2/D3/M5/INDEX/errors.log
  (ex-squelette xfail)

Suite tests/unit : 85 passed, 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:31:38 +02:00
92557d4e74 chore(rgpd): replace CHCB/Bayonne/Saint-Denis/Réunion refs in source + configs (D-12)
Anonymise toutes les références à des entités réelles (CHCB, Bayonne, Saint-Denis,
Réunion, etc.) dans le code source, les configurations YAML, les scripts/outils,
et les tests unitaires. Conserve les tests synthétiques (cases) intentionnels.

- profile key chcb_strict → chuxx_strict
- CHCB → CHUXX, Bayonne → Chicago, Saint-Denis → Springfield,
  Réunion → Province Bêta, 64100/97400 → 12345, FINESS → 999999999,
  préfixe tél 05.59.44 → 0X.XX.XX
- renomme tools/test_chcb_leak.py → tools/test_force_term_leak.py

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 14:39:21 +02:00
3c9d68b49e feat(gui): apply WIP profils+masques+build-windows from stash (2026-04-27)
Application du stash@{0} resté en WIP depuis le 27/04 :
  "On main: wip-gui-profils-masque-manuel-build-windows-2026-04-27"

## Apport

- Pseudonymisation_Gui_V5.py (+1208 lignes) : profils, panneau paramètres
  avancés, éditeur de masques intégré, gestion whitelist/blacklist
- launcher.py (+315) : splash natif PyInstaller, single-instance,
  téléchargement modèles
- anonymisation_onefile.spec : config PyInstaller mise à jour
- pdf_mask_designer.py (+114) : éditeur de masques amélioré
- config_defaults.py (+23) : constantes nouvelles
- tests/unit/test_config_externalization.py (+12) : tests config
- .gitignore (+5)

## Pourquoi

La version courante de la GUI sur la branche feature manquait :
- L'éditeur de masques
- Les profils
- Le panneau paramètres avancés
- Le splash natif au démarrage

Aucun conflit avec mes 10 commits Q-1 (pas de chevauchement de fichiers).

## Validation

75 passed, 10 xfailed sur pytest tests/unit/.

## Note

Le stash reste disponible dans `git stash list` jusqu'à drop explicite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 11:09:46 +02:00