Files
rpa_vision_v3/docs/CR_AUDIT_SETUP_VISUAL_GUARDS_2026-05-22.md

11 KiB

CR — Durcissement du setup auto Windows (gardes visuelles + skip pixel-change)

Date : 2026-05-22 Branche : backup/post-demo-2026-05-19 Périmètre : agent_v0/server_v1/replay_engine.py, agent_v0/agent_v1/core/executor.py, agent_v0/agent_v1/ui/chat_window.py Statut : patch + tests implémentés et verts (104/104 sur le périmètre).


1. Constat live (run du 22 mai 2026 — replay_sess_76b7d067)

Sur sess_20260520T102916_066851, le trim neutral=True passe correctement (patch 20 mai). En revanche, le setup auto Windows enchaîne ses étapes sans aucune garde visuelle intermédiaire :

  • act_setup_sess_click_start finit en position_fallback (clic blind, sans résolution VLM).
  • Succès jugé sur simple changement d'écran (_wait_for_screen_change dans executor.py:1313).
  • type_search et wait_results partent sans garde de fenêtre.
  • click_app_result découvre trop tard que la fenêtre attendue n'est pas Rechercher mais Fenêtre de dépassement de capacité de la barre d'état système..
  • Pendant ce temps, bloc-notes a déjà été tapé dans la mauvaise surface (le popup overflow), polluant l'état.

2. Cause racine

Deux trous combinés :

# Trou Détail
A Pas de pré/post-conditions visuelles entre les étapes du setup verify_screen côté agent (executor.py:1196) ne faisait qu'un time.sleep et déléguait toute vérification au serveur — qui n'a pas de node CLIP pour ces étapes intermédiaires
B Validation par simple pixel-change sur click_start executor.py:1313 considère un click _setup_phase valide dès qu'un seul pixel change. Or l'overflow popup change l'écran sans pour autant ouvrir le bon menu

3. Patch minimal — nouveau contrat de contrôle visuel

3.1 Nouvelle chaîne setup (12 actions, 3 gardes intermédiaires + 1 finale)

1.  click_start_menu                clic visuel, fallback x/y
2.  wait_start_menu                 1000 ms
3.  verify_start_menu_open          GARDE 1 — titre ∈ {Rechercher, Search,
                                                       Cortana, Démarrer,
                                                       Start, SearchHost,
                                                       StartMenuExperienceHost}
4.  click_search_box                clic visuel  (uniquement si search_mode = click_then_type)
5.  wait_search_ready               500 ms
6.  verify_search_box_active        GARDE 2 — titre ∈ {<title_session_source>,
                                                       Rechercher, Search}
7.  type_app_name                   frappe « Bloc-notes »
8.  wait_search_results             1200 ms
9.  verify_search_results_visible   GARDE 3 — titre ∈ {Rechercher, Search,
                                                       Cortana, SearchHost,
                                                       StartMenuExperienceHost}
10. click_app_result                clic visuel + expected_window_before
11. wait_app_launch                 2000 ms (3000 pour Office)
12. verify_screen final             CLIP node setup_initial (pré-existant)

3.2 Mécanisme des gardes (nouveau champ sur verify_screen)

Champ ajouté sur le contrat verify_screen : expected_window_title_contains: List[str]. Côté agent :

  1. time.sleep d'attente (comportement legacy).
  2. Si patterns présents : get_active_window_info() → comparaison substring case-insensitive avec les patterns.
  3. Match positif → succès, on continue.
  4. Match négatif → bascule en mode apprentissage humain (_capture_human_correction, 120 s).
    • Si l'utilisateur agit : warning setup_guard_window_mismatch, success=True, la correction remonte au serveur.
    • Si timeout : success=False, needs_human=True, pause supervisée.

Pas de changement côté serveur. Le node CLIP final (setup_initial) reste pour le verify post-launch.

3.3 Skip pixel-change pour _setup_phase

Dans executor.py, juste avant la branche _wait_for_screen_change :

is_setup_action = bool(action.get("_setup_phase"))
if needs_screen_check and hash_before and is_setup_action:
    # Setup phase : pixel-change neutralisé, la garde verify_screen tranche
    time.sleep(0.5)
elif needs_screen_check and hash_before:
    # Comportement legacy pour les actions utilisateur
    ...

Conséquences :

  • click_start_menu ne peut plus être validé sur la seule ouverture du systray overflow popup.
  • Le verify_screen suivant détecte le mauvais titre fenêtre et déclenche immédiatement le mode apprentissage.
  • Les actions utilisateur hors setup conservent strictement le comportement précédent (non-régression vérifiée).

3.4 Fix troncature bulle pause supervisée (livré au tour précédent)

Pour mémoire — déjà appliqué :

  • chat_window._compute_paused_bubble_height(reason_str) : helper statique testable.
  • Calcul : max(wrapped_lines, explicit_lines) avec cap à 12 lignes (vs 8 avant).
  • Scrollbar activée dès que cap atteint OU contenu ≥ 200 chars (vs > 280 chars avant).
  • Les longs reason serveur listant plusieurs candidats (avec \n) ne sont plus tronqués silencieusement.

4. Fichiers modifiés

Fichier Modification SCP Windows
agent_v0/server_v1/replay_engine.py _generate_setup_actions : insertion de 3 actions verify_screen (verify_start_menu_open, verify_search_box_active, verify_search_results_visible) Non
agent_v0/agent_v1/core/executor.py Helper statique _window_title_matches_any ; branche verify_screen étendue avec garde titre fenêtre + mode apprentissage ; skip _wait_for_screen_change pour _setup_phase=True OuiC:/rpa_vision/agent_v1/core/executor.py
agent_v0/agent_v1/ui/chat_window.py Helper statique _compute_paused_bubble_height ; cap relevé à 12 lignes, scrollbar dès cap atteint ou ≥ 200 chars (tour précédent) OuiC:/rpa_vision/agent_v1/ui/chat_window.py

⚠️ Le miroir agent_v0/deploy/windows_client/ est obsolète (setup initial uniquement). Canal d'incrémental réel = SCP manuel direct vers C:/rpa_vision/.

5. Tests ajoutés ou adaptés

Fichier Nature Tests
tests/unit/test_env_setup.py NEW classe TestSetupVisualGuards 6 tests : insertion verify_start_menu_open, verify_search_box_active (mode click_then_type), absence en direct_typing, verify_search_results_visible toujours présent (les 2 modes), timeout ≤ 2 s sur toutes les gardes
tests/unit/test_env_setup.py Adaptation de 5 tests existants test_notepad_setup_visual (12 actions), test_skips_search_click_for_direct_typing, test_verify_screen_final_present_with_title, test_no_final_verify_without_title, test_full_pipeline_from_events (séquence canonique mise à jour)
tests/unit/test_executor_verify_window_guard.py NEW fichier 13 tests : helper _window_title_matches_any (7 cas) + routage garde (4 cas : match, mismatch+correction, mismatch+timeout, neutre sans patterns) + skip pixel-change _setup_phase (2 cas : setup skippe, hors-setup garde le comportement)
tests/unit/test_chat_window_paused_dispatch.py Ajout classe TestPausedBubbleHeight (tour précédent) 6 tests : empty, court, long single line, multi-lignes \n, cap atteint, seuil 200 chars
tests/integration/test_replay_session_trim_neutral.py Inchangé (tour précédent) 1 test bout-en-bout — toujours vert avec le nouveau setup

Bilan tests sur le périmètre : 104 / 104 verts.

cd /home/dom/ai/rpa_vision_v3
source .venv/bin/activate
set -a && source .env.local && set +a

python -m pytest \
  tests/unit/test_env_setup.py \
  tests/unit/test_executor_verify_window_guard.py \
  tests/unit/test_chat_window_paused_dispatch.py \
  tests/unit/test_server_client_replay_controls.py \
  tests/integration/test_replay_session_trim_neutral.py -v

6. Comportement attendu en live

Après SCP executor.py + chat_window.py et redémarrage Léa, sur un nouveau /replay-session de sess_20260520T102916_066851 :

Scénario Log Léa attendu Issue
click_start touche le vrai bouton Windows [LEA] verify_screen garde OK : 'Recherche' matche [...] Setup avance, frappe protégée
click_start ouvre systray overflow popup Pixel-change observé MAIS log explicite Setup action … : validation pixel-change skippée (garde verify_screen ultérieure) puis [LEA] verify_screen garde KO : attendu un titre contenant [...], actuel 'Fenêtre de dépassement…' Mode apprentissage humain immédiat, aucune frappe à l'aveugle
Focus perdu pendant wait_search_results (notification surgit) [LEA] verify_screen garde KO sur verify_search_results_visible Apprentissage humain avant click_app_result
Bulle de pause avec un long reason Scrollbar visible Plus de troncature

7. Risques / limites

  • Patterns FR+EN uniquement : couverture Windows 10/11 FR et EN. Sur OS exotique (DE, ES, ZH), il faudra étendre expected_window_title_contains. Localisé dans _generate_setup_actions, extension triviale.
  • Skip pixel-change conditionné à _setup_phase : seules les actions marquées _setup_phase=True perdent la validation pixel-change. Si une future contribution ajoute une action setup sans garde verify_screen derrière, on perdrait le filet. À surveiller / documenter dans la convention de génération.
  • Mode direct_typing : couverture par verify_start_menu_open (avant frappe) + verify_search_results_visible (avant clic résultat). Pas de verify_search_box_active car pas de click_search_box à valider — testé explicitement.
  • Helper _compute_paused_bubble_height : prend en compte les \n explicites et la longueur ; cap 12 lignes. Compromis volontairement conservateur — afficher une scrollbar légèrement trop tôt vaut mieux que tronquer du contenu critique de pause.

8. Synthèse pour décision

  • Avant ce patch : setup auto enchaînait click → wait → type → click_result sans contrôle entre, et un seul changement de pixel suffisait à valider la première étape. Constat live = bloc tapé dans Fenêtre de dépassement…, click_result en erreur tardive, paused_need_help.
  • Après ce patch : 3 gardes verify_screen titre fenêtre + skip pixel-change setup → chaque transition critique est verrouillée. Mode apprentissage humain immédiat à la première dérive. Pixel-change ne décide plus de la validité d'une étape setup.
  • Scope : 2 fichiers prod modifiés (≈ 90 lignes ajoutées dans replay_engine.py, ≈ 75 dans executor.py), 2 fichiers test (≈ 350 lignes neuves + adaptations). Aucun changement côté serveur ni protocole.
  • SCP : executor.py et chat_window.py à pousser vers C:/rpa_vision/agent_v1/… avant relance Léa. replay_engine.py reste côté serveur Linux.
  • Validation live à faire : lancer un /replay-session sur sess_20260520T102916_066851, vérifier la présence des 3 logs verify_screen garde OK (ou un mode apprentissage propre en cas de dérive).