Files
rpa_vision_v3/docs/PLAN_CHANTIER_UNIFICATION_LEA_VWB_2026-06-17.md
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

8.8 KiB

Plan de chantier — Unification Léa + VWB (préparé le 2026-06-17 au soir)

Préparé par analyse multi-agents (3 agents read-only) + graphify, après le check UI post-reboot DGX. Rien n'a été modifié. Document de cadrage pour la reprise. Méthode imposée : chirurgie itérative supervisée (1 modif = 1 test = validation Dom). Pas de batch.

0. Diagnostic corrigé (important — deux hypothèses du soir invalidées)

Le check UI a fait remonter 3 symptômes : T3 (Léa « ne trouve pas » le bloc-notes), T5/anchors (images d'ancres absentes au VWB), et le sujet de fond fonds commun. L'analyse de code rectifie le diagnostic « à chaud » :

Hypothèse du soir Verdict après analyse code
T3 = silo machine_id (Léa-VM ne voit pas le savoir du .11) FAUX au niveau sélection. Le SemanticMatcher ne filtre par aucune machine ; Léa tourne sur le DGX qui héberge les dossiers des deux postes → elle voit déjà tous les workflows.
T3 = filtre is_production_ready FAUX. Aucun composant runtime (matcher, exécuteur, chat) ne lit is_production_ready/learning_state.
Vraie cause T3 Fragmentation de l'apprentissage. 100 répétitions → ~20 workflows distincts nommés d'après les apps vues (« Bloc-notes, Explorateur et Terminal (2)(3)… »), aucun nommé franchement « ouvrir le bloc-notes » → le matching sémantique se dilue sur 20 quasi-doublons. (Le silo existe, mais au niveau renforcement cross-machine, pas sélection.)

Chantier A — Consolidation de l'apprentissage (débloque T3) — PRIORITÉ HAUTE

Cause racine

Chaque session de streaming crée un workflow neuf, sans jamais chercher ni fusionner un existant.

  • Nommage + suffixe (2)(3) : agent_v0/server_v1/stream_processor.py:4335-4344 (_generate_workflow_name) — collision de nom → variante numérotée au lieu de renforcement.
  • Persistance directe sans dédup : stream_processor.py:4417-4445 (_persist_workflow), build :2966-3112 (_build_workflow_from_session).
  • 1 observation / node : build toujours séquentiel (graph_builder.py:345 clusters={i:[i]}), donc observation_count = 1 (graph_builder.py:909). DBSCAN d'agrégation volontairement désactivé.
  • Aucune fonction de merge/dédup de workflows dans tout core/. Le VariantManager (core/variants/variant_manager.py:266, seul code qui fait observation_count += 1) n'est jamais appelé.
  • is_production_ready calculé dans core/training/quality_validator.py:114,238-246 (seuil min_observations_per_node=3) — toujours False car 1 obs/node, mais sans effet runtime (label informatif uniquement).

Leviers (effort / risque / impact)

  • A. Découpler « exécutable » de « production_ready » — faible / faible / moyen — quick-win sémantique.
  • B. Fusion/dédup create-or-update à la persistance — élevé / moyen / fort — cause racine.
  • C. Rebrancher l'agrégation des observations (VariantManager ou _run_cross_session_learning qui réécrit observation_count) — moyen / moyen / fort.
  • D. Seuil min_observations configurable/contextuel — faible / moyen / faible — cosmétique seul.
  • E. workflow_id = signature stable de la trajectoire (hash de la séquence d'actions) au lieu des apps vues — moyen / moyen / fort — supprime le (2)(3) à la racine, rend B trivial.

Reco : E + B (signature stable + create-or-update avec agrégation d'observations), D en complément, A en quick-win si on veut juste « rendre exécutable » vite.

Composants

stream_processor.py (L2966-3112, L4335-4344, L4417-4445, cross-session L3149-3268, list L4518) · graph_builder.py (L345, L909, L384-456) · quality_validator.py (L114, L238) · semantic_matcher.py (sélection) · variant_manager.py (L266, à rebrancher) · replay_learner.py:358 (consolidate = hints seulement, leurre).


Chantier B — Affichage anchors VWB (débloque T5) — FIX PRÉCIS, FAIBLE RISQUE

Cause racine

Le commit b8b963059 n'a corrigé que la moitié : l'import lit target.context_hints.anchor_image_base64 uniquement pour les actions simples.

  • services/learned_workflow_bridge.py : branche action simple else L226-233 (lit le base64, ajouté par le commit) ; les actions compound (majoritaires dans les workflows Léa) passent par _convert_compound_substep L279 qui ne lit jamais le base64 → substeps anchor_id=NULL → frontend affiche « Ancre requise » sans image (frontend_v4/.../StepNode.tsx:113-119).
  • Aggravant état DGX : les workflows en base datent d'avril, 100% des steps anchor_id=NULL → ré-import nécessaire après fix.

Chaîne (pour mémoire)

import api_v3/learned_workflows.py:249 → convert learned_workflow_bridge.py:72save_anchor_image → table visual_anchors (db/models.py:163) → API GET /api/v3/anchor/<id>/thumbnail (api_v3/capture.py:356) → React StepNode.tsx (api.ts:136). Pas de mismatch URL/chemin.

Fix

Propager anchor_image_base64 aux substeps compound (passer target dans la boucle compound L169-187 / _convert_compound_substep, poser l'ancre sur le 1er substep cliquable — éviter de dupliquer sur N substeps). Risque faible/additif. Puis ré-importer les workflows cibles.


Chantier C — Fonds commun / mutualisation cross-poste — STRATÉGIQUE, DÉCISION PRODUIT D'ABORD

État

  • Fédération core/federation/ entièrement débranchée au runtime : GlobalFAISSIndex.search() (faiss_global.py:199) jamais appelé ; endpoints export/import (api_stream.py:6277-6372) sans aucun déclencheur (ni cron, ni frontend).
  • Anonymisation = le maillon le plus mûr et prêt : learning_pack.py exclut machine_id/hostname/patient/nip/ipp (_clean_metadata L410, _SENSITIVE_METADATA_KEYS L61-66), hash SHA-256 (L388), export = embeddings 512d + signatures (pas de pixels/OCR brut).
  • Silo réel = stream_processor._run_cross_session_learning L3197/L3284 (workflow_machine != machine_id → continue) : bloque le renforcement cross-machine.
  • Identité : machine_id workflows = hostname_os (ex DESKTOP-58D5CAC_windows, agent_v1/config.py:34-37) ≠ token enrôlement cbd8f9f0… (agent_registry.py:107-111, sécurité parc). À ne pas confondre.

Options

  • Intra-clinique brut (lever filtre cross-session L3197/L3284, charger toutes machines) — simple, non anonymisé → acceptable seulement intra-site.
  • Cross-clinique anonymisé (brancher search() global + déclencheur export/import + index global peuplé) — la vraie « fédération », effort moyen-élevé, seul canal sûr PII.

Décisions produit à trancher AVANT de coder (pour Dom)

  1. Quel point d'entrée Léa au runtime ? Deux providers concurrents : agent_chat/app.py:678,906 (port 5004, SemanticMatcher sur data/training/workflows/) vs chat serveur api_stream.py:6623 (_list_available_workflows qui liste des sessions live, pas les workflows entraînés). Les logs DGX du soir montrent le 5004 + SemanticMatcher → probablement 5004, à confirmer formellement avant de coder A.
  2. Critère de « même parcours » pour la fusion (levier E/B) : signature de trajectoire ? nom de base ? (workflows de 7 à 89 nodes pour « le même » parcours → alignement non trivial).
  3. Source de vérité workflows (DETTE-015) : DB VWB SQLite (5002) vs JSON data/training/workflows/ — la route /api/workflows de Léa fusionne les deux avec une dédup fragile. Trancher la source canonique.
  4. Niveau de mutualisation : intra-clinique brut (rapide, non anonymisé) vs fonds commun cross-clinique anonymisé (fédération). Implications réglementaires opposées.
  5. Re-exécutabilité des packs fédérés : l'export n'emporte que des squelettes anonymisés (pas les templates/coordonnées) → un chemin de re-résolution visuelle est nécessaire (cohérent avec le contrat 100% vision).

Ordre recommandé pour la reprise

  1. Confirmer le provider runtime de Léa (Q1) — 10 min, read-only, débloque tout le reste.
  2. Chantier B (anchors) — fix ciblé compound + ré-import. Faible risque, gain visuel immédiat (T5).
  3. Chantier A (consolidation) — E + B, chirurgie itérative. Débloque T3 (le bloc-notes « connu »).
  4. Chantier C (fonds commun) — décision produit (Q4) puis implémentation anonymisée. Le plus stratégique pour la proposition de valeur, mais le moins urgent pour une démo.

Garde-fous

  • Tout changement au build/persist (Chantier A) touche le chemin qui alimente la démo Urgence → chirurgie itérative, 1 test par modif.
  • Champ de mines core/ : vérifier le wiring runtime réel avant de rebrancher (VariantManager), pas seulement la présence du code.
  • Mutualisation cross-site = uniquement via LearningPack anonymisé, jamais recopie de JSON bruts (PII : OCR, titres fenêtres patients).