docs: add POC specs, handoffs, and research notes

This commit is contained in:
Dom
2026-06-02 16:28:34 +02:00
parent 18ed6cb751
commit f2e9aac6b7
86 changed files with 27615 additions and 25 deletions

View File

@@ -0,0 +1,552 @@
# AXE D2 — Gestion des modaux & popups imprévus
**Date :** 2026-05-23
**Auteur :** agent recherche (dispatch session principale)
**Périmètre :** stratégie pour gérer en 100% vision les modaux Windows / navigateur / métier qui interrompent un replay Léa.
**Statut :** brief de recherche — aucune modification de code proposée. Décisions = Dom.
---
## 1. TL;DR + recommandation architecture
### 1.1. Diagnostic
- Le projet a déjà 80% de l'outillage : `core/grounding/dialog_handler.py` (EasyOCR + InfiGUI + fallback OCR direct) couvre la **résolution** d'un dialog connu.
- Trois lacunes documentées :
1. Côté **client Léa**, `_handle_possible_popup` est défini avec **0 site d'appel** (`LESSONS_LEARNED_GHT_2026-05.md`, F5.5.1) — il existe également un `_handle_popup_vlm` qui prend le relais mais sans déclencheur générique.
2. Pas de **détecteur d'apparition** (la cascade ne sait pas qu'un modal vient d'apparaître — elle continue à viser l'élément initial, qui est désormais masqué).
3. Pas de **politique de fail-safe** différenciée par type de modal (UAC ≠ "fichier déjà existe" ≠ Windows Hello).
- Anti-pattern interdit (`feedback_100pct_visual.md`) : inventer un raccourci Win+R / Ctrl+X / Échap-systématique. La cascade reste **OCR → template → VLM**, jamais "réflexe magique".
### 1.2. Recommandation
Une stack en trois couches, branchée APRÈS chaque action (et au démarrage du tick d'observation), réutilisant le code existant :
```
ChangeDetector ──► DialogClassifier ──► DialogResolver
(léger, < 50ms) (OCR titre + LLM) (catalogue déclaratif
+ InfiGUI/OCR + escalation)
```
1. **ChangeDetector** — détecte qu'un modal *vient d'apparaître*. Combinaison foreground-window-change (Windows API côté client) + screenshot diff région centrale + heuristiques visuelles (ombre, centrage). Latence cible < 50 ms.
2. **DialogClassifier** — décide *quoi faire* (catalog match → action déterministe ; sinon → VLM pour catégoriser). Réutilise `_read_title` + `KNOWN_DIALOGS` du `dialog_handler.py` actuel, étend avec une catégorisation par type (`UAC` / `HELLO` / `SMARTSCREEN` / `BROWSER_PERM` / `METIER_SAVE` / `INCONNU`).
3. **DialogResolver** — applique la **matrice modal → action** (§5). En santé : aucun auto-accept système (UAC/Hello/SmartScreen) — uniquement pause supervisée. Auto-dismiss déterministe **uniquement** pour les modaux métier déclarés dans le workflow (ex. "fichier déjà existe → Oui").
Cette stack résout **mécaniquement** la dépendance avec AXE_B2 (Validator) : un modal non détecté = un Validator post-action raté ; un Validator sémantique strict force le détecteur à être appelé avant le verdict.
---
## 2. Taxonomie des modaux Windows 11 / navigateur (mai 2026)
Sept catégories qui couvrent ~95% des cas terrain healthtech.
### 2.1. UAC (User Account Control)
- **Quand** : installation, élévation `runas`, modification système.
- **Aspect visuel** : fond bleu ou assombri global (secure desktop), titre `Contrôle de compte d'utilisateur`, deux boutons `Oui` / `Non` ou champ mot de passe administrateur.
- **Particularité** : sur **secure desktop**, screenshot Léa peut être noir/inaccessible (`pyautogui` ne voit rien). Microsoft a livré des fixes UAC en oct. 2025 → janv. 2026 (KB5063878 / KB5074109) — quelques replays plantent encore sur 24H2 idle/locked.
- **Politique healthtech recommandée** : **JAMAIS auto-accept**. Pause supervisée immédiate.
### 2.2. Windows Hello / WebAuthn / FIDO2
- **Quand** : déverrouillage app sensible (gestionnaire de mots de passe, Outlook), site avec WebAuthn, élévation UAC configurée pour exiger biométrie.
- **Aspect visuel** : popup système centré, icône empreinte ou caméra, message "Touchez le capteur" ou "Saisissez votre code PIN".
- **Particularité** : nécessite **interaction physique humaine** par construction. Aucune solution 100% vision ne peut résoudre. Anti-pattern absolu : tenter de cliquer "Annuler" pour passer outre.
- **Politique** : pause supervisée + **tip** suggérant "désactiver Windows Hello pour la session de démo" en config préalable.
### 2.3. Microsoft Defender SmartScreen
- **Quand** : exe non signé, téléchargement suspect, premier lancement Léa.
- **Aspect visuel** : bandeau bleu ciel "Windows a protégé votre PC", lien "Informations complémentaires" qui révèle le bouton "Exécuter quand même".
- **Politique** : pause supervisée + log security. Notre `feedback_auth_dialogs_runtime.md` rappelle d'anticiper AVANT démo client (signature code, allowlist hash SHA256 — voir `project_code_signing.md`).
### 2.4. Permissions navigateur (caméra, micro, notifications, géoloc, clipboard)
- **Quand** : première visite site `https://`, démo Easily Assure si elle demande accès clipboard / notifications.
- **Aspect visuel** : popup ancrée à l'URL bar (Chrome/Edge), boutons `Autoriser` / `Bloquer`. Variant inline overlay (Edge 2026).
- **Particularité critique sécurité (CVE-2026-0628 janv. 2026)** : malveillances via extensions Chrome qui détournent des permissions. Auto-accept = risque RGPD/HDS.
- **Politique** : **déclaratif dans le workflow** ("À cette étape, autoriser le micro") ou pause supervisée. Aucun auto-accept générique.
### 2.5. Dialog métier (sauvegarde, écrasement, perte de modifications)
- **Quand** : fermeture document non sauvé, "fichier existe déjà", "Voulez-vous quitter ?".
- **Aspect visuel** : popup applicative au-dessus de la fenêtre parente, OCR titre fiable, boutons texte clair (`Oui` / `Non` / `Annuler` / `Enregistrer`).
- **Politique** : **catalogue déclaratif**. C'est exactement ce que `KNOWN_DIALOGS` du `dialog_handler.py` actuel gère. Résolution InfiGUI + fallback OCR direct.
### 2.6. Avertissements / erreurs applicatives (popup OK)
- **Quand** : timeout réseau, validation backend KO, message info-utilisateur.
- **Aspect visuel** : popup centré, icône triangle/croix, un seul bouton `OK` / `Fermer`.
- **Politique** : auto-dismiss déterministe SAUF si message critique (regex blocklist "données perdues", "supprimé"). Log obligatoire.
### 2.7. Modaux inattendus / inconnus (notification push Teams, Outlook reminder, popup mise à jour, cookie banner, newsletter)
- **Quand** : tout le temps, surtout en démo live (Slack ping, Outlook reminder à xx:00, popup Windows Update).
- **Aspect visuel** : très variable. Souvent en coin (toast) plutôt que centré, mais peut voler le focus.
- **Politique** : VLM classifier (catégoriser : "publicité" / "système" / "métier inconnu") → pause supervisée avec proposition humaine ou auto-dismiss conservateur (Échap visuel via clic croix détectée).
---
## 3. Comparaison frameworks 2026
| Framework | Détection modal | Politique | Pause humaine | Catalogue déclaratif |
|---|---|---|---|---|
| **Anthropic Computer Use** (avril 2026) | classifiers anti-prompt-injection détectent screenshots suspects → demande confirmation user | permission-first par défaut, refuse "high-risk", monitor model peut pause | oui (Auto Mode mai 2026 = classifier décide auto-approve vs prompt) | non public |
| **OpenAI Operator / ChatGPT Agent** (juillet 2025 → 2026) | "monitor model" surveille comportement suspect ; CAPTCHA / login → cède le contrôle à l'humain (screenshots OFF pendant ce temps) | confirme avant action critique, prend la main sur prompts sécurité | oui, prend-le-relais explicite | non |
| **Skyvern 2.0** (oct. 2025) | **Validator** regarde écran post-action, détecte "popup blocked the click", redonne main au Planner pour retry | retry visuel ; built-in TOTP / 2FA / file downloads | non documenté publiquement | implicite via Validator |
| **browser-use** (issue #1996 ouvert mai 2026) | **pas de solution intégrée** — la communauté demande explicitement une infra générique | au cas par cas | non | non |
| **Cradle** (R&D fin 2025) | screenshot-only, demande au VLM principal d'identifier popup à chaque tick | dépend prompt | non | non |
| **PopSweeper** (recherche acad. 2024, applicable mobile) | classifier deux étages **ResNet50 + MobileNetV2** + **YOLO-World** pour bouton croix ; image-diff 100 ms tick ; **60 ms par frame** | auto-dismiss centré sur close-button | non | non |
| **rpa_vision_v3 (actuel)** | aucun détecteur ; `dialog_handler.py` ne s'exécute que si appelé explicitement | catalogue déclaratif + InfiGUI/OCR fallback | feedback_failure_is_learning oui | oui (`KNOWN_DIALOGS`) |
**Lecture** :
- Skyvern et OpenAI Operator **valident l'idée centrale** : un Validator strict détecte le modal indirectement (action attendue échoue → l'écran a changé sans cause connue → modal).
- Anthropic et OpenAI **convergent** sur le "monitor model" parallèle qui pause sans toucher au workflow principal.
- PopSweeper démontre qu'un détecteur **léger spécialisé** (CNN custom < 60 ms) suffit pour ne PAS ajouter de coût VLM à chaque tick.
- L'écosystème open source (browser-use) n'a **toujours pas** de solution générique — le sujet est ouvert.
---
## 4. Architecture proposée pour rpa_vision_v3
### 4.1. Vue d'ensemble
```
┌───────────────────────────────────────────┐
│ Léa (Windows client) │
│ │
action click ───►│ executor │
│ │ │
│ ▼ │
│ perform_click │
│ │ │
│ ▼ │
│ ChangeDetector ◄─── screenshot t+1 ──┐ │
│ │ │ │
│ ▼ │ │
│ is_modal_appeared? │ │
│ │ │ │
│ no ┴ yes │ │
│ │ │ │
│ ▼ │ │
│ DialogClassifier │ │
│ │ │ │
│ ▼ │ │
│ type ∈ {UAC, HELLO, SMART, PERM, │ │
│ SAVE, OK, INCONNU} │ │
│ │ │ │
│ ▼ │ │
│ DialogResolver │ │
│ │ │ │
│ ▼ │ │
│ policy(type, workflow_ctx) │ │
│ │ │ │
│ ▼ │ │
│ ┌─ AUTO_DISMISS (OK trivial) │ │
│ ├─ DECLARATIVE (catalog match) │ │
│ ├─ ASK_HUMAN (pause supervisée) │ │
│ └─ ESCALATE_SECURITY (log + pause) │ │
│ │ │
│ ▼ │ │
│ resume_or_wait │ │
│ │ │
└───────────────────────────────────────┘
serveur (api_stream)
report dialog event + replay state
```
### 4.2. Étendre `core/grounding/dialog_handler.py` existant
Le fichier actuel (lecture seule pour ce doc, voir Read) fait déjà :
- `_read_title` (EasyOCR full-screen, `fr+en`, GPU)
- catalogue `KNOWN_DIALOGS` ordonné (popups modaux prioritaires avant fenêtres parents)
- `_click_via_infigui` (UI-TARS / InfiGUI grounder déjà branché)
- `_click_via_ocr` (fallback OCR direct)
- retour `dict` avec `handled / title / dialog_type / action / position / time_ms`
**À ajouter (esquisses, pas de code à committer) :**
```python
# core/grounding/change_detector.py — nouveau fichier proposé
from dataclasses import dataclass
from typing import Optional, Tuple
import time
import numpy as np
@dataclass
class ChangeSignal:
"""Signal qu'un changement écran significatif vient d'apparaître."""
is_modal: bool # heuristique modal vs scroll normal
foreground_hwnd_changed: bool # côté Windows uniquement
diff_ratio: float # 0.0 = identique, 1.0 = tout différent
central_diff_ratio: float # diff zone centrale (modaux centrés)
timestamp: float
class ChangeDetector:
"""Détecte qu'un modal *vient d'apparaître* sans appeler le VLM principal.
Stratégie :
1) foreground window change (Windows API, ~1 ms)
2) screenshot diff centre vs périphérie (numpy diff sur sous-region, ~10 ms)
3) heuristique "centré + bordure assombrie" (modal pattern, ~5 ms)
Budget total cible : < 50 ms pour ne PAS ralentir la boucle replay.
"""
def __init__(self):
self._last_screenshot = None
self._last_hwnd = None
def detect(self, screenshot_pil) -> ChangeSignal:
t0 = time.time()
arr = np.asarray(screenshot_pil.convert("L"))
fg_changed = self._check_foreground_changed()
diff_ratio = 0.0
central_diff = 0.0
if self._last_screenshot is not None:
prev = np.asarray(self._last_screenshot.convert("L"))
if prev.shape == arr.shape:
diff = np.abs(prev.astype(int) - arr.astype(int))
diff_ratio = float((diff > 25).mean())
# zone centrale = modaux Windows typiques
h, w = arr.shape
cy0, cy1 = h // 4, 3 * h // 4
cx0, cx1 = w // 4, 3 * w // 4
central_diff = float((diff[cy0:cy1, cx0:cx1] > 25).mean())
is_modal = (
fg_changed
or (central_diff > 0.10 and diff_ratio < 0.40) # changement centré
)
self._last_screenshot = screenshot_pil
return ChangeSignal(
is_modal=is_modal,
foreground_hwnd_changed=fg_changed,
diff_ratio=diff_ratio,
central_diff_ratio=central_diff,
timestamp=t0,
)
def _check_foreground_changed(self) -> bool:
"""Côté Windows uniquement — sinon retourne False."""
try:
import ctypes # noqa
hwnd = ctypes.windll.user32.GetForegroundWindow()
changed = (self._last_hwnd is not None) and (hwnd != self._last_hwnd)
self._last_hwnd = hwnd
return changed
except Exception:
return False
```
**Note importante** : `feedback_popup_vlm.md` documente que `GetForegroundWindow` est **non fiable seul** (retourne 0 en SSH, popups Windows modernes partagent hwnd du parent). On l'utilise comme **signal complémentaire**, jamais comme source unique. La détection finale repose sur le diff écran (vision).
### 4.3. DialogClassifier — extension du `dialog_handler.py`
```python
# core/grounding/dialog_classifier.py — proposition
from enum import Enum
class DialogType(str, Enum):
UAC = "uac"
HELLO = "windows_hello"
SMARTSCREEN = "defender_smartscreen"
BROWSER_PERMISSION = "browser_permission"
METIER_SAVE = "metier_save" # match catalog KNOWN_DIALOGS
METIER_CONFIRM = "metier_confirm"
OK_TRIVIAL = "ok_trivial" # popup avec 1 seul bouton OK
INCONNU = "inconnu"
# Signatures texte par type (extension du catalogue actuel)
TYPE_SIGNATURES = {
DialogType.UAC: [
"contrôle de compte d'utilisateur",
"user account control",
"voulez-vous autoriser cette application",
],
DialogType.HELLO: [
"windows hello", "saisissez votre code pin",
"touchez le capteur d'empreintes",
],
DialogType.SMARTSCREEN: [
"windows a protégé votre pc",
"smartscreen", "informations complémentaires",
],
DialogType.BROWSER_PERMISSION: [
"autoriser", "bloquer",
"souhaite utiliser votre caméra",
"souhaite utiliser votre microphone",
"souhaite afficher des notifications",
],
# METIER_SAVE et METIER_CONFIRM = KNOWN_DIALOGS existant
}
class DialogClassifier:
"""Classifie un dialogue détecté en type connu.
Stratégie cascade :
1) match signatures texte (OCR titre) — ~150 ms (EasyOCR cache)
2) si pas de match → VLM compact (qwen3-vl:8b) avec prompt
"Classify this dialog: uac / hello / smartscreen / browser_perm /
metier / unknown" — ~1.7 s
3) fallback : INCONNU
"""
def classify(self, screenshot_pil, ocr_text: str) -> DialogType:
text = ocr_text.lower()
for dtype, signatures in TYPE_SIGNATURES.items():
for sig in signatures:
if sig in text:
return dtype
# Catalogue métier existant (KNOWN_DIALOGS du dialog_handler.py)
from core.grounding.dialog_handler import KNOWN_DIALOGS
for key in KNOWN_DIALOGS:
if key in text:
return DialogType.METIER_SAVE # ou METIER_CONFIRM selon key
# Fallback VLM si rien ne matche et qu'on a un signal modal fort
return self._classify_via_vlm(screenshot_pil) or DialogType.INCONNU
def _classify_via_vlm(self, screenshot_pil) -> Optional[DialogType]:
# Appel qwen3-vl:8b via Ollama LAN (port 11434)
# Prompt court, format=json strict
# ⚠ qwen3-vl:8b ignore parfois format=json — fallback regex sur stdout
...
```
### 4.4. DialogResolver — politique par type
Voir matrice §5 ci-dessous. Le resolver applique la politique et émet un événement structuré au serveur :
```python
@dataclass
class DialogEvent:
type: DialogType
title_ocr: str
policy_applied: str # "auto_dismiss" / "declarative" / "ask_human" / "escalate_security"
action_taken: Optional[str] # "click 'Oui' (123,456)" / "paused"
duration_ms: float
screenshot_path: str # toujours archivé pour audit
```
---
## 5. Matrice modal → action
| Type | Détection signature | Politique healthtech | Action concrète | Audit |
|---|---|---|---|---|
| **UAC** | "contrôle de compte", "user account control" | **escalate_security + ask_human** — JAMAIS auto-accept | `pause_for_human` ; toast "élévation requise — opérateur valide" | log full + screenshot |
| **Windows Hello** | "windows hello", "code pin", "touchez le capteur" | **ask_human** — interaction physique requise par construction | pause + tip pré-démo : "désactiver Hello pour la session" (paramètres Windows) | log |
| **Defender SmartScreen** | "windows a protégé votre pc", "smartscreen" | **escalate_security + ask_human** | pause + log security ; rappel `project_code_signing.md` (signature SHA256) | log full |
| **Permission navigateur** (cam/mic/notif/geoloc) | "souhaite utiliser votre", "autoriser / bloquer" | **declarative** si déclaré dans workflow ; sinon **ask_human** | catalog match → click `Autoriser` ; sinon pause | log + screenshot |
| **Métier sauvegarde** ("Voulez-vous enregistrer ?", "Enregistrer sous") | `KNOWN_DIALOGS` existant | **declarative** | InfiGUI click `Enregistrer` (catalog priority basse — fenêtre parent) | log standard |
| **Métier confirmation** ("Voulez-vous remplacer ?", "Existe déjà", "Écraser") | `KNOWN_DIALOGS` priorité HAUTE | **declarative** | InfiGUI click `Oui` ; fallback OCR direct (code actuel) | log standard |
| **OK trivial** (erreur app, info) | 1 seul bouton détecté, mots-clés "erreur/error/warning" ; pas de mot blocklist | **auto_dismiss** | click `OK` | log standard |
| **OK trivial SUSPECT** (mots-clés "supprimé", "perdu", "irréversible") | blocklist regex | **ask_human** | pause | log full |
| **INCONNU** | aucun match | **ask_human** par défaut (pas d'auto-dismiss aveugle) | pause + capture VLM pour catégorisation a posteriori → enrichit catalogue | log full |
**Garde-fou healthtech** : tout dialog non métier listé dans `KNOWN_DIALOGS` ou dans le workflow déclaratif **escalade en pause supervisée** par défaut. C'est cohérent avec `feedback_failure_is_learning.md` (échec = pause, pas stop) et le constat OpenAI/Anthropic 2026 (login/sécurité → cède la main à l'humain).
---
## 6. Détection rapide d'apparition de modal
Trois pistes, à composer plutôt qu'à choisir :
### 6.1. Foreground window change (Windows API)
- **Coût** : ~1 ms.
- **Fiabilité** : faible seul (`feedback_popup_vlm.md` 27 mars 2026 : popups Windows modernes partagent hwnd du parent, retourne 0 en SSH).
- **Usage** : **signal complémentaire** dans `ChangeSignal`, jamais source unique.
```python
import ctypes
hwnd = ctypes.windll.user32.GetForegroundWindow()
title_buf = ctypes.create_unicode_buffer(256)
ctypes.windll.user32.GetWindowTextW(hwnd, title_buf, 256)
# Comparer hwnd_n vs hwnd_n-1 ; titre dans title_buf.value
```
### 6.2. Screenshot diff zone centrale vs périphérie
- **Coût** : ~10 ms (numpy `abs(prev - curr) > seuil`, downscale 1/4).
- **Fiabilité** : bonne pour modaux centrés (UAC, dialog métier, Hello). Faible pour toasts en coin.
- **Heuristique** : `central_diff_ratio > 0.10` **ET** `diff_ratio < 0.40` → modal centré probable (le centre change beaucoup, le reste peu).
- **Pattern visuel auxiliaire** : zone "assombrie" en bordure (`secure desktop` UAC = pixels < 50 en luminance sur > 60% de l'écran).
### 6.3. PopSweeper-style classifier (option future, si latence VLM trop forte)
- ResNet50 + MobileNetV2 deux étages → 60 ms/frame, 91.7% précision sur RICO (mobile).
- À envisager **uniquement** si la détection diff+heuristique laisse passer trop de cas. Pour l'instant, surcoût d'un modèle dédié non justifié — l'OCR titre + signatures couvre 80%.
### 6.4. Pas de pHash global pour détection modal
`feedback_phash_vs_dialog_in_vm.md` est explicite : **pHash global est inadapté** à la cascade de modaux en VM. Le pHash compare des images entières, masquant les changements locaux qui sont précisément l'indice d'un modal. Utiliser screenshot diff zoné OU OCR titre — pas pHash global.
---
## 7. Activation de `_handle_possible_popup` orphelin
### 7.1. État actuel
- **Côté client (Léa Windows)** : `_handle_possible_popup` défini, **0 site d'appel** (`LESSONS_LEARNED_GHT_2026-05.md`, F5.5.1). Un `_handle_popup_vlm` existe en parallèle (le "remplacement" mentionné dans l'audit) mais sans déclencheur générique.
- **Côté serveur** : `core/grounding/dialog_handler.py` (étudié pour ce doc) — handler complet, ne se déclenche que si on l'appelle explicitement.
- **Constat memoire 27 mars 2026** : `qwen3-vl:8b` détecte popup en 3.6 s avec coordonnées précises depuis le client (appel direct LAN port 11434), pas via le serveur. Donc le VLM-post-clic est **techniquement validé**.
### 7.2. Câblage proposé (sans modifier le code dans ce doc)
Le pattern à brancher dans `agent_v1/core/executor.py` ressemble à :
```
def perform_click(self, x, y, ...):
screenshot_before = grab()
do_click(x, y)
time.sleep(short_delay)
screenshot_after = grab()
signal = ChangeDetector().detect(screenshot_after)
if signal.is_modal:
ocr_text = read_ocr(screenshot_after)
dtype = DialogClassifier().classify(screenshot_after, ocr_text)
event = DialogResolver(policy).resolve(dtype, screenshot_after, workflow_ctx)
report_to_server(event)
if event.policy_applied == "ask_human":
return WAIT_HUMAN
return OK
```
**Sites d'appel à brancher** (à valider avec Dom avant tout commit) :
1. Après chaque `_replay_action` côté client (suit la mémoire 27 mars).
2. Avant chaque vérification de Validator post-action (cohérence AXE_B2).
3. Au démarrage du tick d'observation `observe_reason_act` côté serveur (capture un modal apparu pendant un wait long).
### 7.3. Décision sur `_handle_popup_vlm` vs `_handle_possible_popup`
À trancher avec Dom : garder UN seul handler (probablement `_handle_popup_vlm` qui appelle l'extension proposée ici), supprimer l'orphelin. Sinon dette technique persistante (DETTE-XXX à créer si décision prise).
---
## 8. Anti-patterns à proscrire
### 8.1. Hardcoder un raccourci système "fix"
`feedback_100pct_visual.md` est sans appel : **JAMAIS** :
- `keyboard.press_and_release('escape')` pour "fermer un popup".
- `keyboard.press_and_release('win+r')` pour "ouvrir un truc rapidement".
- `keyboard.press_and_release('ctrl+x')` pour "annuler".
Raisons :
- Casse le récit "Léa comprend visuellement". Démontage immédiat face à un DSI healthtech.
- Échappe à la cascade de validation (OCR → template → VLM).
- Effets de bord imprévisibles : Échap dans un formulaire peut purger des données saisies ; Win+R sur un secure desktop ne fait rien et perd l'état.
**Exception unique** : `gesture_catalog.py` autorise les réflexes système **explicitement référencés** (voir `feedback_lea_reflexes_catalog.md`). Mais c'est une **composition** orchestrée, pas un "fix popup ad hoc".
### 8.2. Auto-accept système (UAC, Hello, SmartScreen)
Interdit en healthtech. Toujours pause supervisée. Cohérent avec FDA / RGPD / HDS — un agent qui élève des privilèges seul est un risque inacceptable.
### 8.3. pHash global pour détecter un modal
Voir §6.4. Utiliser screenshot diff zoné + OCR titre.
### 8.4. Polling VLM principal à chaque tick
Latence Qwen2.5-VL = 8-11 s par appel (synthèse `MIGRATION_VLM_PLAN_2026-05-09.md`). Détection modal doit rester < 100 ms — sinon on bloque la boucle replay. Le VLM est appelé **uniquement** quand le ChangeDetector signale `is_modal=True` ET que le catalogue texte n'a pas matché.
### 8.5. Tenter de "désactiver" Windows Hello programmatiquement
Solution = config humaine pré-démo, pas action runtime de l'agent. L'agent **détecte et escalade**, il ne modifie pas la config sécurité Windows.
---
## 9. Liens forts avec les autres AXES et la dette projet
- **AXE_A4 (OCR/Template/pHash)** : la **détection** modal réutilise screenshot diff zoné — surface à coordonner avec la décision pHash de A4 (pas pHash global ici).
- **AXE_A5 (Screen Tokenization)** : un parser d'écran qui produit la liste de regions interactives détecte aussi les "boutons de modaux" — la classification peut bénéficier de cette liste sans coût VLM supplémentaire.
- **AXE_B2 (Validator)** : dépendance forte. Un Validator strict (texte attendu présent dans la zone visée) **force** l'appel au DialogResolver quand le check post-action échoue. Sans ce couplage, un modal non vu reste un échec silencieux (cf. bug step 10 démo 8 mai : Imagerie cliqué dans bandeau Edge, REPORT success=True).
- **AXE_A3 (Bench Protocol)** : ajouter un harness "modal injection" — pendant un replay test, injecter UAC simulé / popup métier / SmartScreen factice, mesurer detect→classify→resolve latency et taux pause vs auto-dismiss.
- **DETTE existante** : DETTE-008 (`if False:` pré-check VLM par-clic, `observe_reason_act.py:1704-1713`) sera **résolue** par le ChangeDetector léger — on n'a plus besoin d'un VLM par clic, le détecteur fait le filtrage en amont.
- **`feedback_capture_purge_policy.md`** : screenshots de DialogEvent à conserver pour audit (RGPD / HDS) — politique de rétention à valider avec Dom.
---
## 10. Sources (liens cliquables)
### Frameworks comparés (publications, blogs, papers)
- [Anthropic Computer Use tool — docs API](https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/computer-use-tool)
- [Anthropic Claude Desktop browser permissions controversy (avril 2026)](https://www.sovereignmagazine.com/article/anthropic-claude-desktop-browser-permissions)
- [Anthropic — Auto Mode permission classifier (mars 2026)](https://medium.com/@joe.njenga/anthropic-adds-new-claude-code-auto-mode-no-more-permission-modes-52c8094ab742)
- [OpenAI Operator System Card](https://openai.com/index/operator-system-card/)
- [OpenAI ChatGPT Agent System Card — juillet 2025](https://cdn.openai.com/pdf/839e66fc-602c-48bf-81d3-b21eacc3459d/chatgpt_agent_system_card.pdf)
- [ChatGPT Agent — login takeover + screenshot OFF](https://help.openai.com/en/articles/11752874-chatgpt-agent)
- [Skyvern — AI RPA Guide (oct. 2025)](https://www.skyvern.com/blog/ai-rpa-guide-intelligent-browser-automation/)
- [Skyvern — API-less Legacy System Automation (mai 2026)](https://www.skyvern.com/blog/api-less-system-automation-tools-legacy-enterprise/)
- [Skyvern GitHub — Planner-Actor-Validator](https://github.com/Skyvern-AI/skyvern)
- [browser-use — Issue #1996 : Need Robust Strategy for Handling Dynamic Popups (ouvert mai 2026)](https://github.com/browser-use/browser-use/issues/1996)
- [OmniParser V2 — Microsoft Research](https://microsoft.github.io/OmniParser/)
- [OmniParser arXiv 2408.00203](https://arxiv.org/abs/2408.00203)
- [UI-TARS arXiv 2501.12326](https://arxiv.org/abs/2501.12326)
### Détection popup, classifiers légers
- [PopSweeper — arXiv 2412.02933 (déc. 2024)](https://arxiv.org/abs/2412.02933)
- [PopSweeper — HTML lecture directe](https://arxiv.org/html/2412.02933v1)
- [ShowUI — arXiv 2411.17465 (2B GUI grounding)](https://arxiv.org/pdf/2411.17465)
- [ZonUI-3B cross-resolution GUI grounding](https://arxiv.org/pdf/2506.23491)
### Sécurité Windows 11 / browser
- [Microsoft KB UAC fixes oct. 2025 → janv. 2026 — Microsoft Q&A](https://learn.microsoft.com/en-nz/answers/questions/5733506/windows-uac-prompt-becomes-unresponsive-after-cred)
- [NinjaOne — Change UAC Behavior Windows 11](https://www.ninjaone.com/blog/change-uac-behavior-for-administrators-in-windows-11/)
- [CVE-2026-0628 Chrome Gemini Live panel takeover](https://news.corksafetyalerts.com/chrome-flaw-allowed-extensions-to-hijack-googles-ai-assistant-camera-and-microphone/)
- [AI-powered phishing leveraging camera/mic permissions (2026)](https://www.scworld.com/brief/ai-powered-phishing-campaign-leverages-hardware-access-for-data-theft)
### Safety gates / human-in-the-loop healthcare
- [Agentic Workflow Approval Gate Framework (4 gate types)](https://www.digitalapplied.com/blog/agentic-workflow-approval-gate-framework-governance)
- [AI Agents for Healthcare — Architecture and Safety Guide (Momentum)](https://www.themomentum.ai/blog/ai-agents-healthcare-architecture-safety-implementation)
- [Human-in-the-Loop Agentic AI (Elementum)](https://www.elementum.ai/blog/human-in-the-loop-agentic-ai)
### Références internes (à charger en parallèle de ce doc)
- `docs/SYNTHESE_TECHNOS_REPLAY_2026-05-23.md` (synthèse maîtresse)
- `docs/LESSONS_LEARNED_GHT_2026-05.md` (zones popup F5.5.1, F6.1.1, DETTE-008)
- `core/grounding/dialog_handler.py` (commit `487bcb861`)
- `memory/feedback_popup_vlm.md` (VLM post-clic, pas ctypes seul)
- `memory/feedback_lea_reflexes_catalog.md` (gesture_catalog autorisé, pas hardcode ad hoc)
- `memory/feedback_phash_vs_dialog_in_vm.md` (pas pHash global)
- `memory/feedback_100pct_visual.md` (jamais raccourci inventé)
- `memory/feedback_auth_dialogs_runtime.md` (anticiper Hello/UAC/Basic Auth AVANT démo)
---
## 11. Hors-périmètre de ce doc
À demander à Dom si besoin avant action :
- Décision finale sur unification `_handle_possible_popup` orphelin vs `_handle_popup_vlm` (les deux côté client).
- Politique de rétention RGPD/HDS des screenshots `DialogEvent` (par défaut `data/runner_captures/dialogs/` purge ACK serveur).
- Choix exact du modèle VLM compact pour la classification fallback (qwen3-vl:8b acceptable mais ignore parfois `format=json` Ollama — voir §2.4 synthèse).
- Bench de la latence `ChangeDetector` sur capture réelle 2560×1600 (cible < 50 ms à vérifier empiriquement).
- Politique sur la suppression auto de toasts (Teams, Outlook) pendant démo : déclaratif "do not disturb" en amont vs détection runtime.
---
*Document de recherche. Lecture seule. Toute mise en code = décision explicite Dom puis chirurgie itérative supervisée (CLAUDE.md projet).*