docs(beta): audit prêt-bêta GUI V6 + design de mise en prod bêta testeur
Audit prêt-pour-bêta de GUI V6 (3 axes : parcours/UX/PII, moteurs/OnnxTR/frozen, licence/télémétrie/diffusion) → punch-list P0=7 / P1=11 / P2=6, findings vérifiés. Design validé Dom : périmètre « A + chaîne prod », P0 + P1 honnêteté UI, toggles « Données à détecter » câblés au moteur (gating par type + couplage rescan, pas de plancher dur), licence souple + binding poste (D-20.4), −2 Go via excludes PyInstaller, Linux-first TDD + un seul build Windows. Plus 3 exigences prod intégrées : diagnostics logs auto-upload scrubbé (liste-blanche), mise à jour propre (installeur), modèles embarqués hors-ligne. 6 chantiers (A-F), 2 repos. Diffusion = gate Dom. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
161
docs/beta/2026-06-25_audit-pret-beta-gui-v6.md
Normal file
161
docs/beta/2026-06-25_audit-pret-beta-gui-v6.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# Audit prêt-pour-bêta — GUI V6 (HEAD `4b7c8db`, 2026-06-25)
|
||||
|
||||
Périmètre : GUI V6 (`gui_v6/`) + chaîne prod (licence, télémétrie, diffusion) pour
|
||||
une mise en bêta testeur. Cible : un testeur installe l'EXE Windows → active sa
|
||||
licence → traite des PDF/images médicaux → ses stats remontent au portail.
|
||||
|
||||
Audit en 3 axes (parcours/UX/PII, moteurs/OnnxTR/frozen, licence/télémétrie/diffusion).
|
||||
Findings vérifiés dans le code (lignes citées) ; les 2 plus lourds recontrôlés par Claude.
|
||||
|
||||
**À FAIRE par Dom : valider / élaguer cette liste avant tout code (cocher / barrer).**
|
||||
|
||||
---
|
||||
|
||||
## P0 — Bloqueurs bêta (à corriger avant toute diffusion)
|
||||
|
||||
### P0-1 — Fuite PII silencieuse : la GUI ne fait pas fail-close si le NER obligatoire échoue
|
||||
- `gui_v6/engine_bridge.py:222-231` appelle `ensure_loaded()` sans vérifier l'état ;
|
||||
si CamemBERT-bio ne charge pas (`:173-175` → `UNAVAILABLE`, `camembert=None`), le
|
||||
traitement continue en **regex + gazetteers seuls** et le document sort compté
|
||||
« Réussi ». Le rescan résiduel ne couvre PAS les noms de personnes.
|
||||
- Le CLI de prod fait l'inverse : `scripts/anonymize_cli.py:184-198` fail-close (code 3,
|
||||
aucune sortie) si le modèle obligatoire manque.
|
||||
- **Impact** : modèle ONNX corrompu/absent (antivirus, ressource manquante) → PDF qui
|
||||
paraît traité, statut OK, mais noms patients potentiellement en clair. **Risque #1.**
|
||||
- **Fix** : dans `process_fn`, si `use_local_ner` et état `UNAVAILABLE` → lever une
|
||||
exception explicite (refus de traitement), le runner la remonte en échec. Aligne la
|
||||
GUI sur la garantie code-3 du CLI.
|
||||
|
||||
### P0-2 — Chaîne prod cassée : la GUI pointe `http://localhost`, jamais le portail réel
|
||||
- `Pseudonymisation_Gui_V6.py:57` → `AnonymisationApp()` sans client → `gui_v6/app.py:41`
|
||||
`LicenseClient("http://localhost")`. La télémétrie réutilise cette URL (`app.py:199`).
|
||||
Aucune env var / config / injection build ne fixe l'URL portail (grep exhaustif = 0).
|
||||
- **Impact** : sur un poste testeur, activation licence ET télémétrie POSTent sur
|
||||
`localhost` → rien n'écoute → **activation impossible, stats jamais remontées**. Toute
|
||||
la « chaîne prod » demandée est non fonctionnelle. Le portail tourne sur
|
||||
`app.aivanov.eu` (vérifié live, HTTPS 200, artefact servi).
|
||||
- **Fix** : injecter l'URL réelle (`DEFAULT_PORTAL_URL="https://app.aivanov.eu"` ou env
|
||||
var), `localhost` devient le secours dev. **Impose un rebuild** (l'EXE déjà publié est
|
||||
inutilisable pour l'activation).
|
||||
|
||||
### P0-3 — Gain −2 Go non réalisé : `optimum` réintroduit torch en dur
|
||||
- `requirements.txt:3` = `optimum[onnxruntime]>=2.0.0` ; optimum déclare `torch>=1.11`
|
||||
en dépendance **cœur** (vérifié). Le build installe requirements → torch dans le venv →
|
||||
PyInstaller le bundle malgré le retrait des hiddenimports (`4b7c8db`). EXE ~+2 Go.
|
||||
- `optimum` n'est importé que par `ner_manager_onnx.py` (legacy ONNX **non câblé** à la
|
||||
GUI), `Pseudonymisation_Gui_V5.py` (V5 legacy) et un script de finetune — **jamais par
|
||||
`gui_v6/`** (le NER GUI = `camembert_ner_manager` en onnxruntime brut).
|
||||
- **Fix** : retirer `optimum` (et hiddenimports `optimum*`) du build frozen GUI ;
|
||||
valider « torch-free » par la **taille EXE réelle** + grep de l'arbo PyInstaller, pas
|
||||
par le diff du spec.
|
||||
|
||||
### P0-4 — Build non reproductible : pas de précache des poids OnnxTR
|
||||
- `anonymisation_gui_v6_onefile.spec:50-67` **raise** `FileNotFoundError` si les poids
|
||||
`db_resnet50` + `crnn_vgg16_bn` absents du cache ; `scripts/build_windows_oneclick.ps1`
|
||||
ne télécharge jamais ces poids. Le build « marche » seulement grâce au cache résiduel
|
||||
de la machine 192.168.1.11.
|
||||
- **Fix** : étape pré-PyInstaller : `python -c "from onnxtr.models import ocr_predictor;
|
||||
ocr_predictor(det_arch='db_resnet50', reco_arch='crnn_vgg16_bn')"` + doc.
|
||||
|
||||
### P0-5 — Crash frozen ONNX probable : le hotfix CLI `6c6f653` non reporté au launcher GUI
|
||||
- Le launcher V6 ne pose pas `ANON_SKIP_LEGACY_ONNX_MANAGER=1` (lu à l'import du core,
|
||||
`anonymizer_core_refactored_onnx.py:211`) et ne pré-charge pas CamemBERT — alors que le
|
||||
hotfix CLI (`scripts/anonymize_cli.py:87`) le fait pour éviter « cannot load module more
|
||||
than once per process » en frozen Windows.
|
||||
- **Fix** : poser le flag tout en haut de `Pseudonymisation_Gui_V6.py` + pré-charger
|
||||
CamemBERT avant le 1er import du core. **À confirmer sur l'EXE** (non reproductible en dev).
|
||||
|
||||
### P0-6 — Contrôle de licence purement décoratif (décision Dom requise)
|
||||
- Enforcement nul : `tab_usage.py:205` active « Lancer » selon le nombre de documents
|
||||
seulement ; aucune gate sur le statut licence (lu pour affichage uniquement).
|
||||
- Pas de vérif locale : `license_client.py:208-213` lit `license.json` **sans vérifier
|
||||
signature ni `machine_id`** → fichier copiable sur N postes = N licences « actives ».
|
||||
- `machine_id` = MAC seule 12 chars (`machine_id.py:12-14`) = clonable, change en VM.
|
||||
- D-20.1 (fingerprint multi-composants) et D-20.4 (vérif locale machine_id) **non
|
||||
implémentés**. La bêta est une fenêtre idéale (aucune activation prod existante à migrer).
|
||||
- **Décision Dom** : niveau d'enforcement bêta (souple / dur / différé) — voir question.
|
||||
|
||||
### P0-7 — Pas de protection multi-instance (lock perdu vs V5)
|
||||
- `Pseudonymisation_Gui_V6.py:50-59` lance `mainloop()` sans file-lock `msvcrt.locking`
|
||||
(présent en V5). Double-clic testeur → 2 instances, 2 chargements ONNX, 2 écritures dans
|
||||
le même dossier sortie.
|
||||
- **Fix** : réintroduire le lock V5 + message « application déjà ouverte ».
|
||||
|
||||
---
|
||||
|
||||
## P1 — Forte friction testeur / écarts (à arbitrer pour la bêta)
|
||||
|
||||
- **P1-1 — Dropzone décorative** (`tab_usage.py:103-115`) : zone « déposez vos fichiers »
|
||||
sans glisser-déposer réel. Confusion dès la 1re étape. → câbler DnD (tkinterdnd2) ou
|
||||
retirer la métaphore.
|
||||
- **P1-2 — 7 toggles « Données à détecter » non câblés** (`tab_config.py:351-357`) : les
|
||||
interrupteurs (Noms, DDN, Établissements…) n'ont ni variable ni callback → aucun effet.
|
||||
Promesse UI non tenue. → câbler au moteur ou rendre informatifs (lecture seule).
|
||||
- **P1-3 — Import/Export config désactivés « à venir »** (`tab_config.py:817-840`) alors
|
||||
que le Partage est mis en avant. Régression vs workflow email V5. → câbler ou retirer.
|
||||
- **P1-4 — `config_path` jamais transmis** (`app.py:155-162`, `tab_usage.py:53,176`) : le
|
||||
`dictionnaires.yml` externe éditable n'est pas garanti chargé en frozen (pas de copie au
|
||||
1er lancement). Personnalisations établissement potentiellement ignorées.
|
||||
- **P1-5 — Erreurs/quarantaine sans pointeur** (`tab_usage.py:268,282`) : « échec » /
|
||||
« quarantaine » sans indiquer où est le doc non livré (`_*_failed/`). → afficher le
|
||||
chemin sortie + bouton « ouvrir le dossier ».
|
||||
- **P1-6 — Pas de validation d'inscriptibilité du dossier de sortie** (`processing_runner.py:214`) :
|
||||
dossier en lecture seule → tout le lot échoue par doc avec message cryptique. → test
|
||||
d'écriture en amont.
|
||||
- **P1-7 — Version app incohérente** : `gui_v6/__init__.py:11` = `6.0.0-g1` vs artefact/note
|
||||
bêta `2026.06.18.1203` (remonte aussi en télémétrie). → aligner sur le schéma de release.
|
||||
- **P1-8 — Runbook non exécutable tel quel** : republier impose un rebuild après P0-2 (le
|
||||
SHA de `note-beta-client.md` deviendra caduc). → ajouter étape « vérifier URL portail
|
||||
embarquée » au runbook.
|
||||
- **P1-9 — Clé de signature licence = clé dev auto-générée** (`app_aivanov/app/signing.py`) :
|
||||
KEY_ID « dev », paire RSA régénérée si volume recréé → licences invalidées. → provisionner
|
||||
une clé prod stable avant d'activer la vérif de signature côté client.
|
||||
- **P1-10 — Politiques VM (D-20.2) / dossiers partagés (D-20.3) non implémentées** (décision
|
||||
Dom, marquées « DECISION REQUIS » dans D-20). Acceptable de différer en bêta interne — à acter.
|
||||
- **P1-11 — Audit JSONL `original="docTR"`** (`anonymizer_core_refactored_onnx.py:5356`) :
|
||||
trace de provenance périmée (OCR = OnnxTR) visible dans le livrable d'audit. → `"OnnxTR"`.
|
||||
|
||||
---
|
||||
|
||||
## P2 — Polish (best-effort)
|
||||
|
||||
- **P2-1 — Étapes de progression statiques** (`tab_usage.py:144-147`) : pastilles
|
||||
Extraction/Détection/Masquage/PDF décoratives ; pas de feedback intra-document.
|
||||
- **P2-2 — Cartes format de sortie décoratives** (`tab_usage.py:118-127`) : suggèrent un
|
||||
choix alors que la sortie est toujours PDF+TXT. → présenter comme « sorties produites ».
|
||||
- **P2-3 — Commentaires/docstrings docTR périmés** (`anonymizer_core_refactored_onnx.py:55,102`) :
|
||||
cosmétique, comportement OK.
|
||||
- **P2-4 — `os_info` non envoyé à l'activation** (`license_client.py:161-164`) : perte d'info
|
||||
diagnostique mineure.
|
||||
- **P2-5 — Contact / canal de retour vide** dans `docs/beta/note-beta-client.md:36`.
|
||||
- **P2-6 — `/api/v1/version` ne déclenche pas de download** (`tab_about.py:164-178`) : le
|
||||
testeur va manuellement sur le portail. Acceptable bêta.
|
||||
|
||||
---
|
||||
|
||||
## Verdicts positifs (ne pas re-traiter)
|
||||
|
||||
- **Télémétrie RGPD : irréprochable.** Double filtrage liste-blanche (`usage_telemetry.py:72`,
|
||||
`_ALLOWED_DOC_KEYS`) + recalcul serveur Pydantic strict. Aucun nom/chemin/texte ne peut
|
||||
fuiter. Non bloquante (thread daemon, timeout 4 s, spool best-effort). App utilisable
|
||||
hors-ligne.
|
||||
- **Pipeline cœur fail-closed correct** : quarantaine moteur → échec, `SEUIL_RESCAN_RESIDUEL=0`,
|
||||
`redact_pdf_raster` pas dans un `except: pass`. La fuite P0-1 vient du **wiring GUI**, pas du cœur.
|
||||
- **engine_bridge / affichage moteurs** : logique « n'afficher que les moteurs embarqués »
|
||||
saine et cohérente avec OnnxTR (OCR) + CamemBERT-bio (NER onnxruntime). 0 référence docTR
|
||||
dans les chaînes affichées à l'utilisateur.
|
||||
- **Câblage `ONNXTR_CACHE_DIR` frozen** : chemins concordants, fail-closed si OnnxTR absent.
|
||||
- **Portail déployé et fonctionnel** : `app.aivanov.eu` HTTPS, artefact servi, download
|
||||
authentifié (licence active requise). Le serveur n'est pas le problème — le client n'y est
|
||||
pas connecté.
|
||||
|
||||
---
|
||||
|
||||
## Décompte : P0 = 7 · P1 = 11 · P2 = 6
|
||||
|
||||
## Synthèse pour décision
|
||||
Le « complet pour prod bêta » est **plus que rebuild + ship** : la chaîne prod est
|
||||
aujourd'hui **non fonctionnelle bout-en-bout** (P0-2 localhost, P0-6 licence décorative),
|
||||
il y a un **risque PII #1** (P0-1 fail-open), et le **−2 Go n'est pas acquis** (P0-3 optimum).
|
||||
Rien de rédhibitoire : findings nets, fixes ciblés. C'est un vrai chantier de finition +
|
||||
câblage, pas une réécriture.
|
||||
161
docs/superpowers/specs/2026-06-25-gui-v6-beta-prod-design.md
Normal file
161
docs/superpowers/specs/2026-06-25-gui-v6-beta-prod-design.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# GUI V6 → prod bêta testeur — design
|
||||
|
||||
**Date** : 2026-06-25 · **Branche** : `feature/q1-quarantine-mvp` · **HEAD de départ** : `4b7c8db`
|
||||
**Statut** : design validé Dom (cadrage + décisions ci-dessous), prêt pour plan d'implémentation.
|
||||
|
||||
## 1. Objectif
|
||||
|
||||
Amener **GUI V6** (`gui_v6/`) à une **mise en prod bêta testeur** complète : un testeur
|
||||
non-technique installe l'EXE Windows → **active sa licence** → traite des PDF/images
|
||||
médicaux → ses **statistiques d'usage remontent au portail** `app.aivanov.eu`, et l'équipe
|
||||
peut **récupérer ses logs de diagnostic** (scrubbés) pour analyse. Le CLI est mis de côté
|
||||
(pas abandonné) ; il partage le même core, donc les fixes cœur lui profitent.
|
||||
|
||||
## 2. Périmètre
|
||||
|
||||
**Dans le périmètre (décisions Dom) :**
|
||||
- App finie : correction des 7 P0 + des P1 qui trompent le testeur + UI honnête de bout en bout.
|
||||
- Rebuild Windows OnnxTR / **torch-free** (gain ~2 Go) + smoke.
|
||||
- Chaîne prod : activation licence bout-en-bout + télémétrie qui remonte réellement + diffusion testée.
|
||||
- **Diagnostics** : log fichier V6 + scrubbing PII (philosophie liste-blanche) + **auto-upload portail**.
|
||||
- **Mise à jour propre** : version réelle injectée au build, upgrade en place, app fermée, config préservée.
|
||||
- **Modèles embarqués dans l'EXE** : présents automatiquement à l'install, hors-ligne (déjà le cas, à fiabiliser).
|
||||
|
||||
**Hors périmètre (différé, acté) :**
|
||||
- Enforcement licence **dur** (blocage), anti-VM (D-20.2/3), fingerprint multi-composants
|
||||
(D-20.1), vérification de signature RSA côté client + clé prod stable (P1-9).
|
||||
- **MAJ in-app auto-download** (l'app télécharge+lance l'installeur) — la MAJ bêta se fait par
|
||||
téléchargement manuel de l'installeur depuis le portail.
|
||||
- Onboarding profond : install validée sur site testeur, boucle de retour structurée.
|
||||
- DnD réel = **inclus** (voir D) ; tout le reste P1 non listé + P2 non listés = itération ultérieure.
|
||||
|
||||
## 3. Décisions clés (et pourquoi)
|
||||
|
||||
| # | Décision | Justification |
|
||||
|---|----------|---------------|
|
||||
| D1 | **Licence souple + binding poste** : activation câblée, statut affiché, vérif locale `machine_id` (D-20.4), **pas de blocage** du traitement. | Valide la chaîne sans bloquer un testeur hors-ligne/mal activé. Durcissement post-bêta. |
|
||||
| D2 | **Toggles « Données à détecter » câblés pour de vrai**, défaut tous ON. | Un contrôle visible non fonctionnel **fausse le test humain**. |
|
||||
| D3 | **Pas de plancher dur** : décocher une catégorie relâche masquage **et** filet de sécurité pour cette catégorie ; l'utilisateur assume. | Sinon le toggle reste faussé (quarantaine systématique). `EMAIL/IBAN/IPP` (sans toggle) restent toujours masqués = plancher conservé. |
|
||||
| D4 | **−2 Go via `excludes` PyInstaller** ; validation par **taille EXE réelle**. | `optimum[onnxruntime]` tire `torch` en dép cœur ; legacy non câblé (import déjà sous try/except). |
|
||||
| D5 | **Linux-first TDD, un seul build Windows à la fin** ; P0-5 porte à l'identique le hotfix CLI `6c6f653`. | Minimise les cycles de build chers. |
|
||||
| D6 | **Rebuild = autonome** (build interne + smoke) ; **diffusion (republish portail) = gate Dom**. | Cadrage d'autonomie. |
|
||||
| D7 | **Logs auto-upload scrubbé** : log fichier V6 rotatif + diagnostics **structurés liste-blanche** (type d'exception, étape, code) + redaction ciblée des identifiants de doc connus, envoyés au portail (endpoint `/diagnostics`, auth licence, non bloquant). | Récupération auto pour analyse sans déranger le testeur ; RGPD garanti par la **même philosophie que la télémétrie** (whitelist), pas par un scrub a posteriori d'un log brut. |
|
||||
| D8 | **MAJ = installeur propre** : version réelle injectée au build, AppId fixe (upgrade en place), `CloseApplications`, config/licence préservées (hors dossier install). | Suffit en bêta ; MAJ in-app auto-download différée. |
|
||||
|
||||
## 4. Chantiers
|
||||
|
||||
### A. Sûreté & robustesse cœur
|
||||
- **P0-1 — Fail-close GUI sur NER indisponible.** `gui_v6/engine_bridge.py:make_process_fn`
|
||||
(210-233) : capturer l'état de `ensure_loaded()` ; si `use_local_ner` et état `UNAVAILABLE`
|
||||
(CamemBERT-bio non chargé, `:173-175`) → lever `EngineUnavailableError`. Le runner la remonte
|
||||
en **échec** (doc non livré). Réplique la garantie code-3 du CLI (`scripts/anonymize_cli.py:184-198`).
|
||||
*Test* : factory CamemBERT qui throw → 0 fichier en sortie + statut échec.
|
||||
- **P0-5 — Frozen ONNX.** `Pseudonymisation_Gui_V6.py:main` (50-58, entrée frozen confirmée
|
||||
`anonymisation_gui_v6_onefile.spec:145`) pose `os.environ.setdefault("ANON_SKIP_LEGACY_ONNX_MANAGER","1")`
|
||||
**avant** `from gui_v6.app import AnonymisationApp` (l.55), et pré-charge CamemBERT. *Test* : ordre
|
||||
d'init unitaire ; **confirmation au smoke EXE** (non reproductible en dev Linux).
|
||||
- **P0-7 — Lock multi-instance.** File-lock `msvcrt.locking` (Windows) au début de `main()`,
|
||||
message « application déjà ouverte ». Le nom du mutex est **partagé avec l'installeur** (D8/AppMutex).
|
||||
*Test* : unit mock.
|
||||
|
||||
### B. Chaîne prod — licence + télémétrie
|
||||
- **P0-2 — URL portail.** `DEFAULT_PORTAL_URL = "https://app.aivanov.eu"` injectée à l'entrypoint
|
||||
(override `ANON_PORTAL_URL`) ; `gui_v6/app.py:41` `localhost` devient secours dev. Télémétrie **et
|
||||
diagnostics** héritent de l'URL (`app.py:199`). *Test* : entrypoint construit le client sur l'URL prod.
|
||||
- **P0-6 — Licence souple + binding (D1).** Activation câblée bout-en-bout. Au démarrage :
|
||||
`local_status()` + **comparer `payload.machine_id` au `machine_id` local** ; si mismatch → statut
|
||||
« licence liée à un autre poste » **affiché**, traitement **non bloqué**. *Test* : `license.json`
|
||||
copié (machine_id ≠ local) → statut invalide, traitement fonctionne.
|
||||
|
||||
### C. Build torch-free reproductible + modèles embarqués
|
||||
- **P0-3 — −2 Go (D4).** `excludes=['torch','torchvision','optimum','optimum.onnxruntime','doctr']`
|
||||
aux 3 specs ; `optimum[onnxruntime]` en optionnel commenté dans `requirements.txt`. **Validation =
|
||||
taille EXE réelle + grep arbo PyInstaller pour `torch`**.
|
||||
- **P0-4 — Précache OnnxTR + modèles embarqués (#2).** Étape avant PyInstaller dans
|
||||
`scripts/build_windows_oneclick.ps1` : `ocr_predictor(det_arch='db_resnet50', reco_arch='crnn_vgg16_bn')`
|
||||
(télécharge les 2 poids). Confirme que le spec embarque bien CamemBERT-bio ONNX + poids OnnxTR
|
||||
(`anonymisation_gui_v6_onefile.spec` `datas`) → **modèles présents à l'install, hors-ligne, sans
|
||||
téléchargement** (aucun chemin de download runtime dans `gui_v6/` — vérifié). Doc build mise à jour.
|
||||
|
||||
### D. Honnêteté UI (anti-faussé)
|
||||
- **P1-2 — Toggles « Données à détecter » câblés (D2/D3).** 7 booléens (Noms→`NOM`,
|
||||
DDN→`DATE_NAISSANCE`, Établissements→`ETAB`, Adresses→`ADRESSE`, NIR→`NIR`, Téléphones→`TEL`,
|
||||
N° adhérent→`ADHERENT`), défaut tous ON, fil : `ConfigState` → `EngineSettings` → kwargs →
|
||||
`process_document` → `cfg` (core:2934/5678). Le moteur **gate le masquage par type** ; une catégorie
|
||||
décochée n'est plus masquée. **Couplage sécurité (D3)** : pour les catégories décochées du rescan
|
||||
résiduel (`CRITICAL_PII_KEYS`, core:610 — NIR, TEL, DATE_NAISSANCE), le **rescan est relâché**
|
||||
(pas de fausse quarantaine). `EMAIL/IBAN/IPP` restent toujours masqués. *Tests* : (a) décocher `ETAB`
|
||||
→ établissement non masqué, autres masqués ; (b) décocher `NIR` → NIR en clair + pas de quarantaine ;
|
||||
(c) tous ON → non-régression. **Revue Qwen obligatoire (code sécurité).**
|
||||
- **P1-1 — Glisser-déposer réel** via `tkinterdnd2` (`tab_usage.py:103-115`) + boutons conservés.
|
||||
- **P1-3 — Import/Export config câblés** (`tab_config.py:817-840`), logique merge V5 (`scripts/merge_params.py`).
|
||||
- **P1-4 — `config_path` frozen** : résoudre `dictionnaires.yml` à côté de `sys.executable`, copie au
|
||||
1er lancement, passé en `config_path`.
|
||||
- **P1-5 — Erreurs/quarantaine lisibles** : chemin sortie + mention `_*_failed/` + bouton « ouvrir le dossier ».
|
||||
- **P2-1 / P2-2 (bonus)** : étapes de progression et cartes format **honnêtes** (fonctionnelles ou
|
||||
visiblement non-cliquables).
|
||||
|
||||
### E. Diagnostics & logs (#1, D7)
|
||||
- **E1 — Log fichier V6.** Configurer un log loguru rotatif à chemin connu
|
||||
(`%LOCALAPPDATA%/Aivanov/Anonymisation/logs/anonymisation.log`) dans `Pseudonymisation_Gui_V6.py`
|
||||
**avant** tout import (combiné à l'ordre P0-5). Aujourd'hui V6 n'a **aucun** log fichier → en frozen
|
||||
fenêtré les diagnostics sont perdus. *Test* : le log est créé au chemin attendu.
|
||||
- **E2 — Diagnostics structurés liste-blanche (RGPD).** Un module `diagnostics` qui produit des
|
||||
**événements structurés** (type d'exception, étape moteur, code, durée, version, `run_id`,
|
||||
`machine_id`) — **jamais** de texte de document ni de contenu d'erreur libre. Les identifiants de
|
||||
documents (noms/chemins connus en entrée) sont **redactés** (→ ordinal/hash) partout. Même
|
||||
philosophie que `usage_telemetry._ALLOWED_*`. *Tests* : un run avec noms de fichiers PII → 0
|
||||
nom/chemin/texte dans la charge utile diag.
|
||||
- **E3 — Upload auto.** Client diagnostic (réutilise l'auth licence/`machine_id` comme la télémétrie),
|
||||
`POST /api/v1/diagnostics/report`, **non bloquant** (thread daemon, spool best-effort, timeout court).
|
||||
Hérite de l'URL portail (P0-2). *Test* : échec réseau → traitement non figé, spool écrit.
|
||||
- **E4 — Portail (`app_aivanov`, repo séparé).** Endpoint `/api/v1/diagnostics/report` (Pydantic strict,
|
||||
auth licence/seat, recalcul/validation serveur), stockage, vue admin « Diagnostics par client ».
|
||||
Migration alembic. *Tests web.* **Revue Qwen RGPD.**
|
||||
|
||||
### F. Release, mise à jour & diffusion
|
||||
- **P1-7 + D8 — Version & installeur.** Injecter la vraie version release (schéma `2026.MM.DD.HHMM`,
|
||||
depuis `build_info`) dans `gui_v6/__init__.py` **et** dans `installer/Anonymisation.iss` (`AppVersion`,
|
||||
`VersionInfoVersion`) — aujourd'hui codée en dur `"1.0.0"` / `"6.0.0-g1"` (3 schémas incohérents).
|
||||
- **D8 — MAJ propre.** `Anonymisation.iss` : AppId fixe déjà présent (upgrade en place) ; ajouter
|
||||
`CloseApplications=yes` + `AppMutex=<nom partagé avec P0-7>` pour fermer l'app avant remplacement de
|
||||
l'EXE. Licence/config en `%LOCALAPPDATA%/Aivanov/Anonymisation/` (hors `{app}`) → **préservées**
|
||||
(vérifié). *Test/checklist* : installer N+1 sur N préserve licence+config, version affichée correcte.
|
||||
- Rebuild Windows GUI V6 (192.168.1.11 via ssh-windows) ; **smoke** : `--self-test` ; 1 PDF natif ;
|
||||
1 PDF scanné (`ocr_used=True`) ; **fail-close vérifié** ; **taille EXE mesurée** (−2 Go ?) ; cycle
|
||||
MAJ N→N+1 testé.
|
||||
- **Runbook** `docs/beta/runbook-portail-beta.md` finalisé (+ étape « vérifier URL portail embarquée ») ;
|
||||
**republish portail + MAJ SHA dans `note-beta-client.md` = gate Dom**.
|
||||
|
||||
## 5. Stratégie de tests & non-régression
|
||||
- TDD sur tout le testable Linux : nouveaux `tests/unit/test_gui_v6_*` + extension core (gating par type)
|
||||
+ tests diagnostics/scrubbing. Non-régression suite existante (222+ tests) + gate `synthetic_regression`.
|
||||
- Revue **Qwen** sur les fixes sécurité (P0-1, P0-6, P1-2 gating+rescan) **et RGPD** (F2/F4 diagnostics).
|
||||
- Smoke EXE pour les concerns frozen-only (P0-4, P0-5, taille, cycle MAJ).
|
||||
|
||||
## 6. Critères d'acceptation (definition of done)
|
||||
1. Aucune sortie produite si le NER obligatoire échoue (fail-close GUI = CLI).
|
||||
2. Activation licence fonctionne contre `app.aivanov.eu` ; binding correct ; **non bloquant**.
|
||||
3. Télémétrie d'un run réel **visible au portail** (RGPD : compteurs only).
|
||||
4. Les 7 toggles modifient **réellement** la sortie ; tous ON = non-régression ; décoché = relâché.
|
||||
5. Import/export, DnD, messages d'erreur : **fonctionnels** (zéro contrôle factice).
|
||||
6. **Diagnostic** d'un run **visible au portail**, contenant **0 nom/chemin/texte de document** (RGPD vérifié).
|
||||
7. **Modèles** présents dans l'EXE : OCR + NER fonctionnent **hors-ligne** post-install, sans téléchargement.
|
||||
8. **MAJ N→N+1** : upgrade propre, licence + config préservées, app fermée pendant la MAJ, version correcte.
|
||||
9. EXE rebuildé : self-test OK, OCR scanné OK, **taille −~2 Go confirmée**, 0 « cannot load module ».
|
||||
10. Suite verte, 0 régression, revue Qwen GO (sécurité + RGPD).
|
||||
11. Diffusion portail = **sur GO Dom** uniquement.
|
||||
|
||||
## 7. Risques & points différés
|
||||
- **R1** — P1-2 touche le cœur sécurité : risque de régression de masquage. Mitigation : TDD + gate
|
||||
`synthetic_regression` + revue Qwen ; défaut tous-ON identique à l'existant.
|
||||
- **R2** — Binding `machine_id` MAC-seule **faible** (contournable, fragile en VM). Accepté en souple ;
|
||||
durcissement (D-20.1) différé post-bêta — **signalé**.
|
||||
- **R3** — P0-5 (crash frozen) non confirmable en dev : **dépend du smoke EXE**. Mitigation : portage
|
||||
identique du hotfix CLI connu-bon.
|
||||
- **R4** — Sans signature vérifiée côté client (différé), le binding `machine_id` est éditable à la main :
|
||||
protège de la copie naïve, pas d'un utilisateur déterminé. Acceptable bêta.
|
||||
- **R5** — **RGPD diagnostics** : un log technique peut fuiter de la PII. Mitigation = événements
|
||||
**structurés liste-blanche** (pas de texte libre) + redaction des identifiants de doc + revue Qwen RGPD +
|
||||
défaut conservateur (dans le doute, on ne remonte pas la ligne). C'est le risque RGPD principal du lot.
|
||||
- **Différé** : MAJ in-app auto-download, enforcement dur, anti-VM, signature client, reste P1/P2.
|
||||
Reference in New Issue
Block a user