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>
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>
setup_logging() branche un TimedRotatingFileHandler vers LOG_FILE (rotation
quotidienne + rétention 180j, Règlement IA Art.12) + console. Sous pythonw
(sans console), basicConfig->stderr était perdu => diagnostic terrain aveugle.
main.py appelle setup_logging au démarrage, avec fallback console si le fichier
est indisponible (ne jamais empêcher Léa de démarrer).
TDD: tests/unit/test_agent_v1_logging.py (3 tests RED->GREEN ; module chargé par
chemin pour éviter les imports lourds DETTE-011/013). py_compile main.py OK.
refs DETTE-021
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Symptome (3 incidents 24h les 24/05) : apres relance distante de Lea via SSH,
les polls /replay/next repartent un moment puis s'arretent. Diagnostic :
- agent_v1/ui/smart_tray.py:875 utilise pystray.Icon.run() comme boucle principale
- main.py:132-133 lance _replay_poll_loop et _background_heartbeat_loop en
daemon threads
- Quand Lea est lancee via sshpass sans session interactive Windows, pystray
echoue (pas de systray accessible) et icon.run() sort
- agent.run() retourne, main() retourne, main thread termine
- Les daemon threads meurent avec le main thread (par design Python)
Fix : _headless_keepalive() maintient le main thread vivant via threading.Event
quand agent.run() sort en laissant agent.running=True (cas anormal). Handlers
SIGTERM/SIGINT/SIGBREAK pour shutdown propre.
Invisible en mode interactif normal (icon.run() ne sort jamais).
Pas de modification de smart_tray ni de la cascade visuelle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Démo GHT 8 mai 2026 — Dom utilise UNIQUEMENT Léa V1 sur Windows pendant
la démo (pas le frontend VWB Linux), donc les pause_message du serveur
doivent être visuellement évidents sur l'écran Windows. Modifications
client validées par Dom + redéployées via SCP (procédure 2026-04-28).
1. ui/paused_toast.py (NEW) — Toast Tkinter custom autonome :
Toplevel topmost overrideredirect, fond bleu Léa (#2563EB), 380px,
haut-droite, auto-close 15s, click-to-close. Re-pin -topmost à
100/500/2000 ms (Windows démet le flag quand le focus part). Rate
limit 3s sur message identique. Aucune dépendance externe (tkinter
stdlib uniquement). Thread-safe : root.after si Tk root existe,
sinon Tk dédié dans un daemon thread. Remplace plyer qui s'avère
silencieux sur Windows 11 (Focus Assist + manque app-id COM).
2. ui/chat_window.py — _add_paused_bubble force la visibilité :
La fenêtre Léa démarrait avec root.withdraw() — la bulle paused
était bien rendue mais invisible. Ajout deiconify+lift+focus_force
avant render, plus appel à show_paused_toast en complément.
3. ui/notifications.py — niveau BLOCAGE déclenche aussi le toast :
Quand notify_message reçoit un MessageUtilisateur.BLOCAGE (cible
non trouvée, mode apprentissage, fenêtre incorrecte), appelle
show_paused_toast en plus de plyer. Couvre la branche supervision
client (executor.py:1012) qui ne passe pas par Plan B serveur.
4. core/executor.py — Plan B replay_paused (lignes 1812-1850) :
Intercepte data["replay_paused"]=True dans la réponse /replay/next,
appelle chat_window._add_paused_bubble si _chat_window_ref défini,
sinon fallback notifier.notify. Idempotence via _last_pause_msg_shown
pour ne pas spammer (1 toast par (replay_id, message) unique).
Threshold FIND-TEXT _find_text_on_screen : 0.50 → 0.75 pour rejeter
les faux positifs (placeholders italiques, tabs voisins) et tomber
en mode apprentissage humain plutôt qu'un clic au pif.
5. main.py — Wiring ChatWindow → Executor pour Plan B.
6. tools/test_lea_toast.py + ui/_test_paused_toast.py (NEW) — Scripts
de test isolé pour validation visuelle rapide sans relancer un
replay complet (commande dans les docstrings).
Validé visuellement sur DESKTOP-58D5CAC. Toasts apparaissent en haut-
droite, fond bleu, auto-close 15s. Test isolé Dom : 3 toasts successifs
visibles sans accroc.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Côté client Agent V1 :
- helpers _get_monitors_geometry() / _get_active_monitor_index() via screeninfo
(fallback gracieux [] / None si screeninfo absent)
- _enrich_with_monitor_info() ajouté aux payloads dict de capture_dual,
capture_active_window, et heartbeat_event poussé par main.py
- screeninfo>=0.8 ajouté aux requirements (source + deploy Windows)
- Deploy capturer.py reçoit l'enrichissement de manière additive (pas de
copie verbatim qui aurait introduit BLUR_SENSITIVE absent côté deploy)
Côté serveur :
- import resolve_target_monitor depuis monitor_router (créé en QW1.1)
- /replay/next : enrichissement action.monitor_resolution avant envoi
au client (idx, offset_x/y, w, h, source de la décision)
- live_session_manager.add_event : propagation monitor_index +
monitors_geometry depuis window_capture ET depuis le payload event
brut (cas heartbeat enrichi sans window/window_title)
Cascade de résolution (cf monitor_router.py) :
1. action.monitor_index (hérité de la session source)
2. session.last_focused_monitor (focus actif vu en dernier heartbeat)
3. composite_fallback (offset 0,0) — backward compat strict
Backward 100% : si geometry vide, fallback composite identique au
comportement actuel mss.monitors[0].
Tests : baseline 89/89 préservée, monitor_router 4/4 OK (total 93/93).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Auto-stop : notification 10 min avant, arrêt automatique après MAX_SESSION_DURATION_S (1h)
- Lea.bat : kill des anciens process (python, pythonw, rpa-agent) au démarrage
- LISEZMOI : simplifié pour les collaborateurs (pas de replay, juste collecte)
- Chat server (5004) vérifié fonctionnel
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Popup handling via double appel VLM (détection + localisation précise du bouton)
- Reconstruction texte depuis raw_keys (numpad /, @ AltGr fusionné)
- Clipboard paste pour texte riche, raw_keys pour commandes simples (Win+R)
- Skip des release orphelins dans raw_keys (fix menu Démarrer parasite)
- Auth Bearer sur toutes les requêtes agent → streaming server
- Endpoints /replay/next et /stream/image publics (agent Rust legacy)
- alt_gr ajouté dans _MODIFIER_ONLY_KEYS
- _key_combo_printable_char détecte ctrl+@ comme caractère imprimable
- start.bat tue les anciens process (python + rpa-agent) au démarrage
- Heartbeat avec token Bearer dans main.py et deploy/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Léa se présente comme "assistante basée sur l'intelligence artificielle"
- Dialog consentement avant enregistrement (capture écran/clavier)
- Rétention logs 180 jours (Article 12 + 26(6))
- Bouton ARRÊT D'URGENCE toujours visible (Article 14)
- Transparence mode autonome explicite (Article 50)
- Rapport conformité AI Act en français (docs/CONFORMITE_AI_ACT.md)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CaptureServer : serveur HTTP daemon sur l'agent Windows
- Capture fraîche mss en ~94ms à chaque requête
- Plus de lecture de vieux heartbeats sur disque
- Fallback capture locale si agent indisponible
- Firewall Windows port 5006 configuré
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Suppression du .git embarqué dans agent_v0/ — le code est maintenant
tracké normalement dans le repo principal.
Inclut : agent_v1 (client), server_v1 (streaming), lea_ui (chat client)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>