fix(replay): self-healing Win+D auto au retry 1 (verification_failed)
Audit project-quality-guardian (2026-05-06) Cas #2 : le mécanisme qui invoquait gesture_catalog.win_minimize_all (Win+D) en cas d'échec de grounding a été archivé le 24/04 dans _archive/dead_code_20260424/core/visual/rpa_integration_manager.py (_attempt_self_healing_resolution). Le catalogue agent_chat/gesture_catalog.py:84 reste intact mais orphelin — aucun caller actif. Conséquence : quand une fenêtre/popup obstrue la cible, Léa retente N fois la même action ratée puis pose une pause supervisée, alors qu'un Win+D ("Afficher le bureau") règle souvent le problème en 200 ms. L'audit proposait observe_reason_act.py mais ce module est utilisé uniquement par /execute/instruction (lui aussi sans client actif, Cas #10). Le bon point d'insertion dans le pipeline replay actif est _schedule_retry (replay_engine.py) — la fonction qui construit la liste d'actions à réinjecter en tête de queue avant chaque retry. Modification : Au next_retry == 1 ET reason in ("verification_failed", "no_screen_change"), insertion en tête de queue de : 1. Action key_combo {keys: ["super", "d"]} (format reconnu par agent_v1/core/executor.py:1151), tagué _recovery_gesture: "win_minimize_all" pour audit. 2. Wait 500 ms pour laisser l'OS terminer l'animation Win+D. 3. Le retry de l'action originale. Au retry 2 et au-delà, comportement inchangé (wait 2s + retry). Tests : 27/27 baseline sprint QW verts.
This commit is contained in:
@@ -1432,14 +1432,38 @@ def _schedule_retry(
|
|||||||
# Stratégie de retry selon le numéro
|
# Stratégie de retry selon le numéro
|
||||||
actions_to_insert = []
|
actions_to_insert = []
|
||||||
|
|
||||||
if next_retry == 2:
|
if next_retry == 1 and reason in ("verification_failed", "no_screen_change"):
|
||||||
# Retry 2 : injecter un wait de 2s avant l'action
|
# Auto-recovery par gesture : tenter Win+D ("Afficher le bureau")
|
||||||
wait_action = {
|
# avant le 1er retry quand l'action n'a rien changé à l'écran.
|
||||||
|
# Hypothèse : une fenêtre/popup non bloquante obstrue la cible.
|
||||||
|
# Cf. gesture_catalog.win_minimize_all (agent_chat/gesture_catalog.py:84)
|
||||||
|
# et audit project-quality-guardian Cas #2 — self-healing par gesture
|
||||||
|
# archivé le 24/04 dans _archive/dead_code_20260424/, reconnecté ici
|
||||||
|
# côté serveur dans le pipeline de retry plutôt que dans la cascade
|
||||||
|
# ORALoop (qui n'est plus sur le chemin actif du replay).
|
||||||
|
actions_to_insert.append({
|
||||||
|
"action_id": f"recovery_win_d_{uuid.uuid4().hex[:6]}",
|
||||||
|
"type": "key_combo",
|
||||||
|
"keys": ["super", "d"],
|
||||||
|
"_recovery_gesture": "win_minimize_all",
|
||||||
|
})
|
||||||
|
# Petit wait après Win+D pour laisser l'OS terminer l'animation
|
||||||
|
actions_to_insert.append({
|
||||||
|
"action_id": f"wait_recovery_{uuid.uuid4().hex[:6]}",
|
||||||
|
"type": "wait",
|
||||||
|
"duration_ms": 500,
|
||||||
|
})
|
||||||
|
logger.info(
|
||||||
|
"Auto-recovery : injection Win+D avant retry %d/%d (raison: %s)",
|
||||||
|
next_retry, max_retries, reason,
|
||||||
|
)
|
||||||
|
elif next_retry == 2:
|
||||||
|
# Retry 2 : injecter un wait de 2s avant l'action (loading possible)
|
||||||
|
actions_to_insert.append({
|
||||||
"action_id": f"wait_retry_{uuid.uuid4().hex[:6]}",
|
"action_id": f"wait_retry_{uuid.uuid4().hex[:6]}",
|
||||||
"type": "wait",
|
"type": "wait",
|
||||||
"duration_ms": 2000,
|
"duration_ms": 2000,
|
||||||
}
|
})
|
||||||
actions_to_insert.append(wait_action)
|
|
||||||
|
|
||||||
actions_to_insert.append(retry_action)
|
actions_to_insert.append(retry_action)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user