Commit Graph

525 Commits

Author SHA1 Message Date
Dom
bd1c9d2c8a feat(deploy+bench+ops): DGX vm scripts, Windows RDP launcher, bench cases, agent_chat enable script
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m50s
tests / Tests unitaires (sans GPU) (push) Failing after 1m53s
tests / Tests sécurité (critique) (push) Has been skipped
2026-07-02 13:32:36 +02:00
Dom
6907ecc82f docs: track design docs, plans, audits, coordination infrastructure, handoffs
- 21 docs/*.md: audits, design notes, deployment plans, checklists, memos
- Coordination: ROLES, runbooks (DGX reboot, Lea live), patches, registre, syntheses, systemd, QG template
- Handoffs: 6 Codex handoff documents + README + template
2026-07-02 13:29:58 +02:00
Dom
7dd5c872df chore(gitignore): untrack ephemeral state + ignore large local artifacts
- git rm --cached: .inbox_baseline.txt, .loop_log.txt (coordination ephemeral)
- Add: .agents/, .codex/, agent_chat/state/, graphify/, graphify-out/ (local state/tool)
- Add: webbrowser (11M PostScript artifact), deploy/installer/lea_python_embed_working.tgz (37M)
- Add: benchmarks/computer_use/predictions/ (generated), **/instance/*.db.bak* (runtime backup)
2026-07-02 13:29:21 +02:00
Dom
bb1ea42318 feat(tools): add 7 wired+bench utility scripts (A+B classification)
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m49s
tests / Tests unitaires (sans GPU) (push) Failing after 1m53s
tests / Tests sécurité (critique) (push) Has been skipped
- A (wired, imports project modules): e2e_map_roles, anonymize_demo, grounding_e2e_resolve_engine
- B (orphan projection, standalone benches): enrichment_eval_multi, extract_easily_bench_cases, extract_record_bench_cases, grounding_eval_multi
2026-07-02 13:27:04 +02:00
Dom
b062e2cca7 chore(gitignore): add C-MORT one-shot tools + sanitizer test gitignore list
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m48s
tests / Tests sécurité (critique) (push) Has been cancelled
tests / Tests unitaires (sans GPU) (push) Has been cancelled
2026-07-02 13:24:59 +02:00
Dom
4cb173a8ec chore(coordination+docs): watcher mandat AGENTS.md, recadrage POC CLAUDE.md, dette enrichie, loop script robustifié
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m49s
tests / Tests unitaires (sans GPU) (push) Failing after 1m53s
tests / Tests sécurité (critique) (push) Has been skipped
2026-07-02 13:07:34 +02:00
Dom
882e4e1f3a docs(design+audit): navigate coords consumption gaps + dead code C-MORT audit
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m51s
tests / Tests unitaires (sans GPU) (push) Has been cancelled
tests / Tests sécurité (critique) (push) Has been cancelled
DESIGN_NAVIGATE_COORDS_CONSUMPTION_2026-07-02.md: 3 structural gaps
with code evidence (Gap A/B/C), 2 resolution options with comparative
table, test rouge proposal.

AUDIT_CODE_MORT_2026-07-02.md: 8 C-MORT, 5 B-ORPHELIN, 4 duplicats,
3 QG-gated suppression lots (~1900 lines).
2026-07-02 13:02:04 +02:00
Dom
cac965cef9 test(coords+capture): coords write-only gap (10 tests) + capture I/O + image_chat_cli
test_coords_consumption_gap.py documents 3 structural gaps where
NavigateCoords are written but never consumed. test_capture_io.py and
test_image_chat_cli.py cover capture and chat CLI paths.
2026-07-02 13:01:49 +02:00
Dom
ebed4d7546 feat(vwb): pont R1 import idempotent core→DB par signature trajectoire
Add import_core_workflow_to_db() — create-or-update par signature de
trajectoire (décision produit Dom 23/06). Les workflows source='manual'
sont exclus du filtre de fusion. Inclut test TDD idempotent (ré-import
2× → toujours 1 seul workflow).
2026-07-02 13:01:33 +02:00
Dom
9a8242add5 chore(gitignore): ignore coordination ephemeral dirs + untrack workflows.db
- Add inbox_qwen/, inbox_codex/, inbox_claude/, active/ to gitignore
- Add .inbox_baseline.txt, .loop_log.txt to gitignore
- git rm --cached workflows.db (runtime data, already covered by **/instance/*.db rule)
2026-07-02 13:01:18 +02:00
Dom
f9a0531325 feat(navigation): brique login visuel OCR-ancre + action navigate au replay
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m52s
tests / Tests unitaires (sans GPU) (push) Failing after 1m58s
tests / Tests sécurité (critique) (push) Has been skipped
- core/navigation/ : visual_verifier (presence=OCR, role=VLM ancre sur tokens),
  grounding (OCR-anchor first, VLM fallback, cache coords valide par la vue),
  visual_login (verify_before/after, DETTE-023), action_resolver (pont runtime)
- api_stream/replay_engine : dispatch action navigate server-side,
  never-fail -> needs_review, import depuis core.navigation (boot 5005 garanti)
- 131 tests verts (wiring boot, e2e handler, unit modules)

Chantier Qwen 01-02/07/2026, revue croisee Claude (plan deploy v2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 10:31:44 +02:00
Dom
ab78ae390a chore(version): bump 1.0.1 -> 1.0.2 (fixes client + installeur upgrade-safe)
Nouvelle politique : versionner chaque livrable. 1.0.2 = httpx embed +
capture JPEG + watchdog RDP + MAJ silencieuse (OFF) + installeur voie 1
(preserve identite, tue Lea, backup, purge). Source de verite = config.py
(AGENT_VERSION) + Lea.iss (MyAppVersion).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 00:06:39 +02:00
Dom
e59489e2cd feat(installer): upgrade — backup rollback (hors embed) + purge captures
Complete la voie 1 sur les 2 items de confort/securite du checklist upgrade :
- BACKUP : robocopy code+config vers <app>_backup HORS python-embed/sessions/
  logs (leger, rapide) => filet de rollback manuel si la nouvelle version
  deconne (l'install manuel n'a pas d'A/B auto).
- PURGE : suppression des captures accumulees (agent_v1/sessions) = donnees
  d'apprentissage internes non exploitables cote clinique. Libere le disque ;
  le fix capture JPEG evite la reprise de saturation. Logs conserves (180j).

Valide .11 (upgrade sur etat Emilie) : Lea tuee, identite+serveur preserves,
backup code/config sans embed, 40 PNG purges -> 0, exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 23:58:54 +02:00
Dom
86e31ada34 fix(installer): upgrade-safe voie 1 — preserve identite+config, tue Lea avant copie
Poste clinique (Emilie) = install existante + Lea vive + config reelle
(machine_id lea-4zbgwxty, vrai serveur). L'installeur regenerait config.txt +
machine_id a chaque install => l'upgrade ecrasait l'identite fleet et forcait
la resaisie du serveur/token (Gap 1), et ne fermait pas la Lea en cours =>
DLL python-embed verrouillees (Gap 2).

Voie 1 :
- FindExistingInstallDir + LoadExistingConfig : detecte l'install, pre-remplit
  le wizard avec la VRAIE conf et memorise le machine_id.
- CurStepChanged(ssInstall) : preserve le machine_id existant (pas de regen).
- PrepareToInstall : tue Lea via le PID du lock avant la copie (libere les DLL).

Valide sur .11 (upgrade silencieux sur etat Emilie simule) : machine_id +
serveur preserves, fausse Lea tuee, lock retire, 4 fixes presents, exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 23:48:40 +02:00
Dom
94fd93ad19 chore(build): verifie anyio+typing_extensions dans l'embed (deps transitives httpx)
Le check de completude embed ne verifiait que httpx/httpcore/h11 ; anyio et
typing_extensions (requis par httpx 0.28.1 sous py<3.13) manquaient => import
httpx aurait pu casser a l'install malgre un build vert.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 23:48:40 +02:00
Dom
50f34b5727 merge(client): fixes Lea poste Emilie — httpx embed, capture JPEG, watchdog RDP, MAJ silencieuse (gated OFF)
4 fixes TDD-verts (revue qualite 3 GO + httpx debloque par peuplement embed).
MAJ silencieuse embarquee flag OFF (dormante, quadruple gate). Cible EXE->Julien.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 22:44:40 +02:00
Dom
a1b3062991 chore(config): pin AGENT_VERSION=1.0.1 (config client + template)
Prerequis merge fixes client Lea : la MAJ silencieuse rapporte AGENT_VERSION
au serveur ; on fige explicitement 1.0.1 (defaut du code) cote config livree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 22:44:40 +02:00
Dom
a210e5ee32 feat(update): swap atomique + rollback (Lea.bat) + confirmation boot (main.py)
Implémente le SWAP réel de la MAJ silencieuse (DETTE-022), remplace les stubs :
- updater.apply_update : ARME le swap (extrait le ZIP -> agent_v1_new/ +
  marqueur UPDATE_READY, garde-fou zip-slip). N'écrase JAMAIS le vivant.
- updater.write_boot_ok_marker : désarme le rollback (retire PENDING_BOOT).
- Lea.bat (template + embed généré par configure_embed.ps1) : swap ATOMIQUE
  par renames (agent_v1 -> agent_v1_prev backup ; agent_v1_new -> agent_v1)
  + rollback auto si PENDING_BOOT persiste (boot précédent non confirmé).
- main.py : confirme le boot après 90 s de liveness locale OU quit propre
  (évite un faux rollback ; RPA_BOOT_CONFIRM_DELAY_S surchargeable pour les tests).

Testable (Python) : 45 tests verts. Le swap OS (renames Lea.bat) + le câblage
main.py seront validés par le test Win 11 (step 0 pré-canary, dont le rollback).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:10:34 +02:00
Dom
5d235e49f1 merge: MAJ silencieuse scaffold 2026-07-01 12:37:21 +02:00
Dom
e679804cfd merge: disparition Lea (watchdog) 2026-07-01 12:37:21 +02:00
Dom
e57b54a100 merge: capture JPEG+chemin 2026-07-01 12:37:21 +02:00
Dom
d34c1f2697 merge: httpx build 2026-07-01 12:37:20 +02:00
Dom
61664c9a36 feat(update): scaffold MAJ silencieuse + canary par machine (DETTE-022, gated OFF, swap encore stub)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:36:48 +02:00
Dom
9ab5ed4671 fix(agent): resilience disparition Lea en RDP/Citrix (watchdog session interactive re-affiche le tray)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:36:47 +02:00
Dom
144a5c288a fix(agent): capture JPEG+downscale (allege CPU/disque, frequence intacte) + robustesse chemin _background/shots
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:36:47 +02:00
Dom
e3f61de4ad fix(agent): embarquer httpx>=0.27 dans le build embed (orchestrateur Lea muet en clinique)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:36:47 +02:00
Dom
2a1b1ed80e feat(stream): dispatch extract_dossier -> handler serveur
Some checks failed
tests / Lint (ruff + black) (push) Failing after 2m3s
tests / Tests unitaires (sans GPU) (push) Failing after 1m51s
tests / Tests sécurité (critique) (push) Has been skipped
Câble le type d'action 'extract_dossier' dans get_next_action (api_stream)
vers _handle_extract_dossier_action (replay_engine). La brique 3 (OCR ->
gate -> persist dossier VWB) était committée mais non atteignable au runtime
faute de dispatch. Import + elif dédié, timeout 180s, exécuteur non bloquant.

Note: le handler utilise encore l'ancienne chaîne (extract_grid + gate maison).
Le remplacement par l'extraction ancrée (map_roles/vlm_client) est une modif
séparée côté replay_engine (ma zone).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 11:05:22 +02:00
Dom
f09b8b8cfd feat(extraction): client vLLM serveur (image+prompt -> texte, post_fn injectable)
Factorise un client propre pour la lecture d'écran : downscale image (fenêtre
max_model_len), thinking off, post_fn injectable (testable sans vLLM). Sert de
vlm_client à extract_dossier_from_image dans le handler runtime. 4 tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 18:03:26 +02:00
Dom
6a78a0059b feat(extraction): extract_dossier_from_image — orchestrateur OCR->VLM->qualite (injectable)
Enchaine ocr_fn -> tokens_from_grid -> map_roles -> assess_quality. OCR et client
VLM injectables (testable hors-ligne, import OCR lazy = module reste pur). C'est la
brique que le handler runtime extract_dossier appellera. 4 tests (35 au total role_mapper).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:26:16 +02:00
Dom
813b33b47e feat(update): DETTE-022 — noyau MAJ silencieuse client Léa (gated, swap en stub)
Logique PURE testée : parse_version semver (R3), decide_update code-only/full (R2),
should_update client (double garde anti-downgrade), download_update (staging only +
SHA256, downloader injectable). Endpoint GET /api/v1/agents/update/check gated
(RPA_AUTO_UPDATE_SERVER_ENABLED). Flags client+serveur OFF par défaut.
Swap fichiers / Lea.bat / restart = STUBS no-op réservés révision humaine.
34 tests TDD. refs DETTE-022

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:21:35 +02:00
Dom
a50057d499 fix(dashboard): DETTE-024 — download fleet, fallback legacy rendu visible
_resolve_lea_zip_template() reste résolu à la volée (full buildé après démarrage OK) ;
ajout d'un WARNING explicite quand le full est absent et qu'on retombe sur le ZIP
léger non autoportant (plus de fallback silencieux). Fonction injectable pour tests.
4 tests + 32 non-régression verts. refs DETTE-024

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:20:28 +02:00
Dom
3ed9798f06 feat(agent_v1): log shipper — remontee auto des logs vers le serveur (gated OFF)
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m43s
tests / Tests unitaires (sans GPU) (push) Failing after 1m51s
tests / Tests sécurité (critique) (push) Has been skipped
LogShipperHandler + LogShipper : buffer borne, flush par batch <= max, resilience
0-perte (rejeu sur echec), sender injectable. Flag RPA_LOG_SHIP_ENABLED (defaut
off, activable par config.txt sans rebuild). Sanitizer client = identite (rempart
PII = serveur, cf commit precedent). Wiring gated dans main.py. 8 tests TDD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 13:30:08 +02:00
Dom
b65710ae43 feat(server): assainissement PII des logs clients à la réception
sanitize_log_entries (réutilise anonymize_text, mapping partagé = tokens cohérents),
branché dans POST /api/v1/agents/logs avant le store : message + logger tokenisés,
ts/level préservés. 7 tests TDD. Rempart PII central du push-log (couvre les postes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 13:30:08 +02:00
Dom
509a026cfc feat(extraction): assess_quality — statut qualité dossier (4 niveaux)
complete / partial / needs_review / failed (priorité décroissante), matching
rôle requis insensible casse+espaces, seuil min_confidence paramétrable (0.6).
16 tests ajoutés (31 au total, verts). Brique TDD via sous-agent, code révisé.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 11:42:14 +02:00
Dom
a62b720144 feat(extraction): map_roles — orchestrateur VLM ancrage strict (client injectable)
build_role_prompt (modes libre / guidé par rôles), parse_vlm_json (robuste :
tolère les fences, {} si invalide), map_roles (prompt -> VLM -> parse -> reconstruct).
Client VLM injecté => testable hors-ligne. 6 tests unit ajoutés (15 au total).
Non branché au runtime (brique validée isolément).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 11:34:43 +02:00
Dom
14b1bf844a feat(extraction): role_mapper — reconstruction de champs ancrée OCR (0 hallucination)
Le VLM ne fournit que des value_ids ; la value est reconstruite côté Python
depuis l'OCR (le texte VLM est ignoré) -> 0 hallucination par construction.
9 tests unitaires : ancrage, ids hors plage, dédup ordonnée, value_ids vide,
confidence min, bbox englobante, anti-injection. Module pur, non branché runtime.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 10:38:11 +02:00
Dom
c82829f2bb feat(server): R1 — import auto du workflow appris vers la DB VWB (gated)
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m44s
tests / Tests unitaires (sans GPU) (push) Failing after 1m49s
tests / Tests sécurité (critique) (push) Has been skipped
finalize_session appelle _maybe_import_to_vwb : si RPA_R1_AUTO_IMPORT (OFF par
défaut), le workflow appris est assaini (sanitize_workflow_dict) puis importé en
DB VWB rejouable via le pont idempotent (import_core_workflow_to_db), dans un
app-context VWB lazy mutualisé (vwb_db). NON bloquant : un échec n'interrompt
jamais la finalisation. Rend l'appris rejouable sans geste manuel (R1).
Tests : câblage du seam + gating du flag + non-régression.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 17:44:24 +02:00
Dom
6075717353 feat(server): durcissement sanitizer PII (chevauchements + GXD5 + workflow_dict)
- Résolution des chevauchements par priorité de détecteur + longueur : corrige le
  FN où, sur 'Dossier/Patient NOM (NAISSANCE) Prénom', le nom de naissance fuyait. (Qwen)
- RE_GXD5_DIAG : tokenise le numéro de dossier ([DOSSIER_n]) ET le nom ([NOM_n]) dans
  'GXD5 Diagnostics - <num> - NOM PRENOM' — 3 patients fuyaient en prod clinique, 0 FP. (Qwen)
- sanitize_workflow_dict : assainit les champs texte d'un workflow appris (by_text, noms)
  avant import en DB VWB (canal apprentissage). Utilisé par R1. (Claude)
14 tests verts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 17:44:24 +02:00
Dom
13f760a3b9 feat(extraction): handler extract_dossier + pont worker→DB VWB mutualisé (brique 3)
vwb_db.py : couplage worker→DB VWB lazy (app Flask sur instance/workflows.db)
mutualisé (R1 + extraction), + persist_extracted_dossier (grille → Job/Table/Field).
replay_engine.py : handler _handle_extract_dossier_action — lit le screenshot,
extrait une grille structurée, gate qualité conservatrice (complete|needs_review),
persiste avec preuve (screenshot_ref/bbox/confidence). N'échoue JAMAIS le replay.
Données patient EN CLAIR (canal extraction, non anonymisé).

Réserve : dispatch runtime (api_stream.py) non encore branché — étape suivante,
à coordonner. Brique 3/4 de la verticale extraction dossier patient.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 14:18:08 +02:00
Dom
9883cad012 feat(extraction): modèle DB dossier patient extrait (Job/Table/Field)
ExtractionJob -> ExtractedTable -> ExtractedField (SQLAlchemy, cascade), avec
preuve par cellule (bbox + confidence) réutilisant la sémantique VWBEvidence,
et statut dossier needs_review|complete. Brique 2 de la verticale extraction.
Documenté : ce canal conserve les données patient EN CLAIR (≠ canal
apprentissage anonymisé) — aucune anonymisation ne doit cibler ces colonnes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 12:47:03 +02:00
Dom
5ed5ae2d4b feat(extraction): lecture de tableau structurée (grille bbox+confiance)
Nouvelle extract_grid_from_image() : reconstruit une grille List[List[cell]]
(lignes ET colonnes par clustering des centres y/x des tokens EasyOCR), en
conservant bbox + confiance + (row,col) par cellule. Contrairement à
extract_table_from_image (liste plate, coordonnée x jetée) — laissé intact.
Brique 1 de la verticale extraction dossier patient.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 12:46:48 +02:00
Dom
7fb58195fb fix(workflow): conserve machine_id au round-trip to_dict/from_dict
Les workflows rechargés du disque retombaient sur machine_id='default' :
to_dict ne sérialisait pas l'attribut d'instance _machine_id et from_dict ne
le reposait pas (il dormait dans metadata['machine_id']). to_dict le sérialise
si présent (pas de 'default' parasite) ; from_dict le restaure depuis le champ
explicite ou metadata (rétrocompat des workflows déjà sur disque).
Test de non-régression round-trip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 11:05:10 +02:00
Dom
fccc06e4a2 feat(server): floute aussi les focus_* (blind spot PII)
Les screenshots focus_* (plein écran, ~1440 fichiers/350 Mo) contenaient des
titres PII non floutés. La condition de blur serveur les inclut désormais,
au même titre que shot_*_full et heartbeat_*. Brut conservé, version _blurred
produite en parallèle. (blind spot relevé par Qwen, revue 28/06)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 11:05:10 +02:00
Dom
6461f0a21b feat(server): câble sanitize_event au chokepoint stream_event (PII)
Assainissement PII appliqué une seule fois à l'entrée de stream_event(),
avec un mapping de tokens par session (cohérence intra-session). Les chemins
de persistance et de traitement (jsonl, worker.process_event_direct,
shadow_observe_event, enrichissement SOM) consomment tous la copie assainie
au lieu de l'event brut — plus aucune PII patient en clair côté serveur.

Test de non-régression du câblage: stream_event ne doit jamais écrire de PII
brute (IPP/contenu saisi) dans live_events.jsonl ni la propager au worker/shadow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 10:39:27 +02:00
Dom
e84cdee393 fix(server): durcissement sanitizer PII suite revue adversariale Qwen
- FN-1/2/3 : ajout RE_PRENOM_NOM (« Prénom NOM » inversé sans parens/crochets,
  ex. « Alix DATTIN ») ; 2e mot tout-majuscules -> 0 FP sur « Mozilla Firefox ».
- FN-4 (majeur, 228 events) : sanitize_event scanne désormais les titres
  RÉCURSIVEMENT (vision_info.window_capture.window_title et tout titre imbriqué),
  au lieu de 3 clés top-level hardcodées.
2 correctifs issus de la revue croisée Qwen. 11 tests verts, 0 FP.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 20:24:52 +02:00
Dom
30d8f65e9a feat(server): sanitize_event — assainissement PII au niveau event
sanitize_event(event, mapping) applique le principe « Léa apprend l'interface,
pas la donnée » (décision Dom 28/06) avant persistance :
- text_input -> contenu (text + raw_keys) remplacé par [SAISIE] (option b) :
  résout la fuite la plus grave (contenu médical) SANS NER ni détection ;
- titres de fenêtre (active_window_title + window/to/from.title) : identité
  patient tokenisée (anonymize_text), app/écran gardés ; cohérence par mapping.
Copie défensive (ne mute pas l'event d'origine). 4 tests (9 au total) verts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 19:53:09 +02:00
Dom
8e4d09594c feat(server): assainissement PII couche regex+structurelle (tokens typés cohérents)
pii_sanitizer.anonymize_text() remplace la PII par des tokens typés et
cohérents ([IPP_1], [AGE_1], [NOM_1]) : protège la donnée ET garde la structure
(type de champ) utile à l'apprentissage des variables. Sans modèle, déployable
partout. Filet regex (IPP/NIR/TEL/EMAIL/AGE, repris de anonymisation) + règles
structurelles cliniques (NOM (NAISSANCE) Prénom ; [Nom Prénom] PACS) + blacklist
logiciels anti-FP. 5 tests verts. Couche NER (noms libres) en complément ensuite.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 19:08:43 +02:00
Dom
46ad5973d1 fix(agent_v1): assainissement PII des logs client a la source (push-log-DGX, brique 4)
Remplace dans les logs/print le contenu utilisateur brut par un equivalent
PII-safe via core/log_safe : titres de fenetre -> _title_hash, reponses VLM ->
[len,has_target], metadonnees -> _sanitize_metadata, chemins -> _path_ext,
workflow_name -> _title_hash. 8 fichiers (executor, recovery, captor, streamer,
main, capture_server, activity_panel, window_info_crossplatform).

Audit Qwen complete : ~17 fuites de titre multi-lignes + 2e fuite VLM (print)
non listees ont ete traitees ; localisation par contenu (refs Qwen derivees).

Preserve volontairement : prompts de grounding VLM (vlm_description) ou le titre
est load-bearing (resolution 100% vision) -> ne PAS hasher.
Differe : window_focus_change (verdict apprentissage).
En attente arbitrage Dom : button_text (~11 captions), patterns, champs detail.

py_compile 8/8 OK, imports OK, helper 6/6 vert.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:42:40 +02:00
Dom
4a38000e74 feat(agent_v1): helpers logging PII-safe (push-log-DGX, brique 4)
Module agent_v1/core/log_safe.py — 3 helpers purs pour assainir les logs
client à la source : _title_hash (SHA1[:8], corrélation sans révéler),
_sanitize_metadata (drop title/active_window/window_title), _path_ext
(extension seule). 6 tests unitaires verts. Module inerte (non encore wired) ;
le branchement dans le code runtime suit en étape supervisée.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:24:54 +02:00
Dom
2597ca9110 feat(server): endpoint GET /api/v1/agents/logs/{machine_id} (push-log-DGX, brique 3)
Route de diagnostic dashboard (read-only) : restitue les logs poussés par un
poste, rangés par machine_id. Bearer global ; volontairement sans garde fleet
(consultation d'un poste révoqué/en panne). limit=tail pour borner la réponse.
4 tests d'intégration verts ; store inchangé (briques 1-2 figées).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 10:47:08 +02:00